LUKS and Linux

Encrypting a storage device with LUKS

What is LUKS (Linux Unified Key Setup) ?


Linux Unified Key Setup or LUKS is a disk-encryption specification created by Clemens Fruhwirth in 2004 and originally intended for the Linux operating system.

Generally LUKS operates on Linux and is based on an enhanced version of cryptsetup, using dm-crypt as the disk encryption back end.

dm-crypt is a transparent disk encryption subsystem in Linux kernel versions 2.6 and later. It is part of the device mapper infrastructure, and uses cryptographic routines from the kernel's Crypto API.

dm-crypt can encrypt whole disks (including removable storage media), partitions, software RAID volumes, logical volumes, as well as files.



What is cryptsetup ?


cryptsetup provides commands to use with the Linux Unified Key Setup (LUKS). An Encryption Pass-phrase has to be provided each time the disk is mounted, and only one key can be used per volume; the symmetric encryption key is directly derived from the supplied pass-phrase.

In the following examples, we will show you how to encrypt a disk using LUKS/cryptsetup on Debian based systems and Red Hat based systems (Ubuntu/Mint/CentOS/Fedora).


Debian based systems installation commands


Debian Based systems: Ubuntu/Mint will need to install the following cryptsetup package.
The following example is taken from an Ubuntu 14.04 LTS system:

Commands issued:

sudo apt-get update
sudo apt-get install cryptsetup


Output:



john@ubuntu1404:~$ sudo apt-get install cryptsetup
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  cryptsetup-bin libcryptsetup4
The following NEW packages will be installed
  cryptsetup cryptsetup-bin libcryptsetup4
0 to upgrade, 3 to newly install, 0 to remove and 35 not to upgrade.
Need to get 273 kB of archives.
After this operation, 848 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://gb.archive.ubuntu.com/ubuntu/ trusty/main libcryptsetup4 amd64 2:1.6.1-1ubuntu1 [77.0 kB]
Get:2 http://gb.archive.ubuntu.com/ubuntu/ trusty/main cryptsetup-bin amd64 2:1.6.1-1ubuntu1 [80.4 kB]
Get:3 http://gb.archive.ubuntu.com/ubuntu/ trusty/main cryptsetup amd64 2:1.6.1-1ubuntu1 [115 kB]
Fetched 273 kB in 0s (845 kB/s) 
Preconfiguring packages ...
Selecting previously unselected package libcryptsetup4.
(Reading database ... 265673 files and directories currently installed.)
Preparing to unpack .../libcryptsetup4_2%3a1.6.1-1ubuntu1_amd64.deb ...
Unpacking libcryptsetup4 (2:1.6.1-1ubuntu1) ...
Selecting previously unselected package cryptsetup-bin.
Preparing to unpack .../cryptsetup-bin_2%3a1.6.1-1ubuntu1_amd64.deb ...
Unpacking cryptsetup-bin (2:1.6.1-1ubuntu1) ...
Selecting previously unselected package cryptsetup.
Preparing to unpack .../cryptsetup_2%3a1.6.1-1ubuntu1_amd64.deb ...
Unpacking cryptsetup (2:1.6.1-1ubuntu1) ...
Processing triggers for man-db (2.6.7.1-1) ...
Processing triggers for ureadahead (0.100.0-16) ...
ureadahead will be reprofiled on next reboot
Setting up libcryptsetup4 (2:1.6.1-1ubuntu1) ...
Setting up cryptsetup-bin (2:1.6.1-1ubuntu1) ...
Setting up cryptsetup (2:1.6.1-1ubuntu1) ...
update-initramfs: deferring update (trigger activated)
Processing triggers for libc-bin (2.19-0ubuntu6.3) ...
Processing triggers for ureadahead (0.100.0-16) ...
Processing triggers for initramfs-tools (0.103ubuntu4.2) ...
update-initramfs: Generating /boot/initrd.img-3.13.0-35-generic

Red Hat based distribution installation commands


The following "yum" command is used to install the "cryptsetup" package to our Red Hat based CentOS installation.

Command issued: yum install cryptsetup -y



[root@centos07a ~]# yum install cryptsetup -y
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirror.bytemark.co.uk
 * extras: mirrors.coreix.net
 * updates: www.mirrorservice.org
Resolving Dependencies
--> Running transaction check
---> Package cryptsetup.x86_64 0:1.6.3-2.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
 Package             Arch            Version                Repository     Size
================================================================================
Installing:
 cryptsetup          x86_64          1.6.3-2.el7            base          110 k

Transaction Summary
================================================================================
Install  1 Package

Total download size: 110 k
Installed size: 237 k
Downloading packages:
cryptsetup-1.6.3-2.el7.x86_64.rpm                          | 110 kB   00:00     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : cryptsetup-1.6.3-2.el7.x86_64                                1/1 
  Verifying  : cryptsetup-1.6.3-2.el7.x86_64                                1/1 

Installed:
  cryptsetup.x86_64 0:1.6.3-2.el7                                               

Complete!

Create a Partition on an unused disk


The following procedure is the same for both Red Hat based distributions and Debian based distributions. The only difference is that you do not need to prefix the commands with "sudo" on Red Hat based systems as it is assumed that you have logged in as the root user.

In the following example, a 512MB virtual disk has been created. You can however use a USB device or any other portable storage device. The disk utility "fdisk" has been used during this exercise for creating any necessary partitions.


Identify Disk using "fdisk -l"


Whenever working with storage, it is important to make sure that you have identified the correct device. The "fdisk -l" command is used to display disks available to your system. This maybe disks in use and disks allocated but not used (have no partitions).

Output from "fdisk -l" command



john@ubuntu1404:~$ sudo fdisk -l
[sudo] password for john: 

Disk /dev/sda: 10.7 GB, 10737418240 bytes
255 heads, 63 sectors/track, 1305 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000628fb

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048      499711      248832   83  Linux
/dev/sda2          501758    20969471    10233857    5  Extended
/dev/sda5          501760    20969471    10233856   8e  Linux LVM

Disk /dev/sdb: 536 MB, 536870912 bytes
255 heads, 63 sectors/track, 65 cylinders, total 1048576 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Disk /dev/sdb doesn't contain a valid partition table

Disk /dev/mapper/ubuntu--vg-root: 9403 MB, 9403629568 bytes
255 heads, 63 sectors/track, 1143 cylinders, total 18366464 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Disk /dev/mapper/ubuntu--vg-root doesn't contain a valid partition table

Disk /dev/mapper/ubuntu--vg-swap_1: 1073 MB, 1073741824 bytes
255 heads, 63 sectors/track, 130 cylinders, total 2097152 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Disk /dev/mapper/ubuntu--vg-swap_1 doesn't contain a valid partition table

From the above we can see that we have a device called "/dev/sdb" that has not been used. This is the disk we are going to use for our example.


Creating a Partition on Disk


In the following example we are going to use "fdisk" to create a standard Linux partition on device /dev/sdb.



john@ubuntu1404:~$ sudo fdisk /dev/sdb
[sudo] password for john: 
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xfb0b3262.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p): p
Partition number (1-4, default 1): 
Using default value 1
First sector (2048-1048575, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-1048575, default 1048575): 
Using default value 1048575

Command (m for help): p

Disk /dev/sdb: 536 MB, 536870912 bytes
255 heads, 63 sectors/track, 65 cylinders, total 1048576 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xfb0b3262

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1            2048     1048575      523264   83  Linux

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

In the above we specified that the disk we are going to be working with is known as "/dev/sdb". We next issued the command "n" via the interactive menu system to create a new partition. Next we specified "p" to indicate we are creating a "Primary" partition. We then accepted the default disk sizes (in this example we used all available space). From the main command menu we issued "p" to display our chosen configuration. And, finally we issued the command "w" to write our changes out. If you do not write your changes out they will be lost when you quit fdisk.



Verify the new partition using "fdisk -l"


We may now use the "fdisk -l" command to verify our new partition. As this is the first partition assigned to our device /dev/sdb it is indicated as "/dev/sdb1" (Partition Number 1 on device /dev/sdb).



john@ubuntu1404:~$ sudo fdisk -l

Disk /dev/sdb: 536 MB, 536870912 bytes
70 heads, 4 sectors/track, 3744 cylinders, total 1048576 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xfb0b3262

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1            2048     1048575      523264   83  Linux

Overwrite Disk with Random Data


The following step is optional, however, it recommended for portable devices as it will help hide the layout of data on the disk.

We will use the "dd" command to write random data to our device "/dev/sdb1" as follows:

Warning: Make sure you issue this command against the correct device as all data will be overwritten!



john@ubuntu1404:~$ sudo dd if=/dev/urandom of=/dev/sdb1 bs=1M
[sudo] password for john: 
dd: error writing ‘/dev/sdb1’: No space left on device
512+0 records in
511+0 records out
535822336 bytes (536 MB) copied, 35.4854 s, 15.1 MB/s

Create a LUKS partition using luksFormat


The next step in this exercise is to format our partition using the command option "luksFormat as follows:



john@ubuntu1404:~$ sudo cryptsetup luksFormat /dev/sdb1

WARNING!
========
This will overwrite data on /dev/sdb1 irrevocably.

Are you sure? (Type uppercase yes): YES
Enter passphrase: 
Verify passphrase:

Note: You have to type "YES" in uppercase letters, lowercase will not be accepted!


Create a Mapping Name


To create a mapping name, we use the "luksOpen" command option and pass a name to our specified device. In this example I am using a mapping name of "MyEncData". You may use any name for this. You will also need to provide the passphrase that you created in the previous step.



john@ubuntu1404:~$ sudo cryptsetup luksOpen /dev/sdb1 MyEncData
Enter passphrase for /dev/sdb1: 

We can now verify our mapping device by issuing the "ls -l /dev/mapper" command as follows:



john@ubuntu1404:~$ ls -l /dev/mapper
total 0
crw------- 1 root root 10, 236 Sep 29 20:50 control
lrwxrwxrwx 1 root root       7 Sep 29 21:24 MyEncData -> ../dm-2
lrwxrwxrwx 1 root root       7 Sep 29 20:50 ubuntu--vg-root -> ../dm-0
lrwxrwxrwx 1 root root       7 Sep 29 20:50 ubuntu--vg-swap_1 -> ../dm-1

john@ubuntu1404:~$ ls -la /dev/mapper/MyEncData 
lrwxrwxrwx 1 root root 7 Sep 29 21:24 /dev/mapper/MyEncData -> ../dm-2

Create a Filesystem on the Encrypted Device


Before we can use our encrypted device, you will need to create a filesystem. This is achieved using the "mkfs" command. In the example below I have used a filesystem type of "ext4". You may use a different filesystem type if you wish.



john@ubuntu1404:~$ sudo mkfs.ext4 /dev/mapper/MyEncData
mke2fs 1.42.9 (4-Feb-2014)
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
Stride=0 blocks, Stripe width=0 blocks
130560 inodes, 521216 blocks
26060 blocks (5.00%) reserved for the super user
First data block=1
Maximum filesystem blocks=67633152
64 block groups
8192 blocks per group, 8192 fragments per group
2040 inodes per group
Superblock backups stored on blocks: 
	8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done 

Mounting the Encrypted Device


To mount our device, we first have to provide a mount point. This is done by creating a directory using the "mkdir" command and then using the "mount" commands as follows:



john@ubuntu1404:/$ cd /
john@ubuntu1404:/$ sudo mkdir private
john@ubuntu1404:/$ sudo mount /dev/mapper/MyEncData /private

We can verify that the device is now mounted by issuing the "df" command as follows:



john@ubuntu1404:/$ df -hT
Filesystem                  Type      Size  Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-root ext4      8.5G  6.3G  1.8G  79% /
none                        tmpfs     4.0K     0  4.0K   0% /sys/fs/cgroup
udev                        devtmpfs  483M  4.0K  483M   1% /dev
tmpfs                       tmpfs     100M  928K   99M   1% /run
none                        tmpfs     5.0M     0  5.0M   0% /run/lock
none                        tmpfs     497M  152K  497M   1% /run/shm
none                        tmpfs     100M   36K  100M   1% /run/user
/dev/sda1                   ext2      236M   76M  148M  34% /boot
/dev/mapper/MyEncData       ext4      485M  2.3M  454M   1% /private

From the above output we can see that the "/dev/mapper/MyEncData" is mounted on "/private"


Verify the Status of a LUKS Device


You can use the "status" option to display the current status of a LUKS device as follows:



john@ubuntu1404:/private$ sudo cryptsetup -v status MyEncData
/dev/mapper/MyEncData is active and is in use.
  type:    LUKS1
  cipher:  aes-xts-plain64
  keysize: 256 bits
  device:  /dev/sdb1
  offset:  4096 sectors
  size:    1042432 sectors
  mode:    read/write
Command successful.

Test device


Below is a quick test of creating a file on the device using the "touch" command:



john@ubuntu1404:/$ cd /private
john@ubuntu1404:/private$ sudo touch sample.data
john@ubuntu1404:/private$ ls -al
total 5
drwxrwxrwx  2 root root 1024 Sep 29 21:50 .
drwxr-xr-x 24 root root 4096 Sep 29 21:45 ..
-rw-r--r--  1 root root    0 Sep 29 21:50 sample.data

Unmount a LUKS Device


The device can be unmounted by issuing the "umount" command. You will need to follow this process if you wish to remove the device from your system. After successfully unmounting the device you will still need to issue the "luksClose" command.



john@ubuntu1404:/$ cd /
john@ubuntu1404:/$ sudo umount /private

Verify the device is no longer mounted with "df"

john@ubuntu1404:/$ df -h
Filesystem                   Size  Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-root  8.5G  6.3G  1.8G  79% /
none                         4.0K     0  4.0K   0% /sys/fs/cgroup
udev                         483M  4.0K  483M   1% /dev
tmpfs                        100M  928K   99M   1% /run
none                         5.0M     0  5.0M   0% /run/lock
none                         497M  152K  497M   1% /run/shm
none                         100M   36K  100M   1% /run/user
/dev/sda1                    236M   76M  148M  34% /boot

Close LUKS device - "luksClose"


Although the device is no longer mounted, it still needs to be closed. If you issue the "ls /dev/mapper" command, you will see our device is still available.



john@ubuntu1404:/$ ls -l /dev/mapper/MyEncData 
lrwxrwxrwx 1 root root 7 Sep 29 21:25 /dev/mapper/MyEncData -> ../dm-2

Issue the luksClose command option



john@ubuntu1404:/$ sudo cryptsetup luksClose /dev/mapper/MyEncData

We can verify that the device is no longer available by issuing the "ls /dev/mapper" command as follows:



john@ubuntu1404:/$ ls -l /dev/mapper/MyEncData 
ls: cannot access /dev/mapper/MyEncData: No such file or directory

Remounting a LUKS Device


The procedure for re-mounting a LUKS device is as follows:


Open device



john@ubuntu1404:/$ sudo cryptsetup luksOpen /dev/sdb1 MyEncData
Enter passphrase for /dev/sdb1: 

Mount Device


Mount device to an existing mount point.



john@ubuntu1404:/$ cd /
john@ubuntu1404:/$ sudo mount /dev/mapper/MyEncData /private

john@ubuntu1404:/$ cd /private

john@ubuntu1404:/private$ ls -l
total 0
-rw-r--r-- 1 root root 0 Sep 29 21:50 sample.data

Changing a Passphrase for LUKS device


You may wish to add/remove a passphrase. This can be done with the following commands "luksAddKey" and "luksRemoveKey".


luksAddKey <device> [<key file with new key>]

              adds  a  new passphrase. An existing passphrase must be supplied
              interactively or via --key-file.  The new passphrase to be added
              can  be  specified  interactively or read from the file given as
              positional argument.

luksRemoveKey <device> [<key file with passphrase to be removed>]

              Removes the  supplied  passphrase  from  the  LUKS  device.  The
              passphrase  to  be  removed  can  be specified interactively, as
              positional argument or via --key-file.

Example Output:



john@ubuntu1404:/private$ sudo cryptsetup luksAddKey /dev/sdb1 
Enter any existing passphrase: 
Enter new passphrase for key slot:

john@ubuntu1404:/private$ sudo cryptsetup luksRemoveKey /dev/sdb1 
Enter passphrase to be deleted: