Encrypted /home on Fedora

You can make the entire physical volume encrypted, and then initrams will take care of access to encrypted PV. LVM and rest OS will not feel that encryption exists at all. You can read about that here. This may even be the preferred method for most systems, but not for my workstation. Every time I create, start and destroy the number of virtual machines. Total encryption will compromise performance on my old magnetic disk. Moreover, there is no valuable information for encryption.

That's why I decided to only encrypt my /home. I do not want anyone to benefit from my (if) a stolen workstation.

Creating encrypted volume

Create LV:

# lvcreate -n home -L 20g /dev/rootvg
# wipefs -a /dev/rootvg/home

Now encrypt LV before creating FS:

# cryptsetup luksFormat /dev/rootvg/home

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

Are you sure? (Type uppercase yes): YES
Enter passphrase: 
Verify passphrase:
# cryptsetup isLuks /dev/rootvg/home && echo Success
Success
# cryptsetup luksDump /dev/rootvg/home

According to dump, a Key Slot 0 is in use by passphrase you've entered while setup encryption.

Now, lets open encrypted volume manually and populate it:

# cryptsetup luksOpen /dev/rootvg/home home
Enter passphrase for /dev/rootvg/home:
# ls -l /dev/mapper/home 
lrwxrwxrwx. 1 root root 7 May 19 19:29 /dev/mapper/home -> ../dm-4

The last options of cryptsetup luksOpen command is a handy name. The resulting /dev/mapper/home appear.

# mkfs.ext4 -j -m0 /dev/mapper/home
 ..
# mount /dev/mapper/home /mnt
# rsync -av --one-file-system /home/ /mnt/
# umount /home /mnt ; mv /home /home.old ; mkdir /home
# mount /dev/mapper/home /home

Make encrypted FS mounted in boot time

Edit /etc/crypttab and add the following line:

# cat /etc/crypttab
# name device passphrasefile options
home /dev/rootvg/home none luks,x-systemd.device-timeout=0

First field is a handy name, next is a device to be opened. Third field is a passphrase containing file (will decribe later), currently "none" for manual passphrase input. Fourth field is a mount options, most interesting is x-systemd.device-timeout=0 that means waiting forever for passphrase input.

Tell systemd to rescan configuration files and generate new service, then check the results:

# systemctl daemon-reload
# find /var/run/systemd/generator | grep cryptsetup
/var/run/systemd/generator/dev-mapper-home.device.requires/systemd-cryptsetup@home.service
/var/run/systemd/generator/cryptsetup.target.requires
/var/run/systemd/generator/cryptsetup.target.requires/systemd-cryptsetup@home.service
/var/run/systemd/generator/dev-rootvg-home.device.wants/systemd-cryptsetup@home.service
/var/run/systemd/generator/systemd-cryptsetup@home.service

Close the encrypted device manually and check whether the system is able to manage it.

# umount /dev/mapper/home
# cryptsetup luksClose home
# ls -l /dev/mapper/home
ls: cannot access '/dev/mapper/home': No such file or directory
# systemctl start systemd-cryptsetup@home.service
Please enter passphrase for disk rootvg-home (home)! **********************
# ls -l /dev/mapper/home
lrwxrwxrwx. 1 root root 7 May 19 21:30 /dev/mapper/home -> ../dm-4

If you now reboot, you will be prompted to enter a passphrase at boot time, and /dev/mapper/home will be activated. However, it will not be mounted, because nothing has been added to the /etc/fstab. Let's add it before rebooting:

# grep home /etc/fstab
/dev/mapper/home        /home   ext4    x-systemd.device-timeout=0 1 2

Mount encrypted disk automatically

You can save the passphrase in a file and avoid entering the passphrase manually at each boot. When can this be useful? Perhaps, if you have a root file system located in a secure place, while a remote attached drive is not. Then you can encrypt a remote disk with a passphrase located in the protected root file system.

Generate some random garbage to file:

# dd if=/dev/urandom of=/root/.passphrase bs=32 count=1
# chmod 600 /root/.passphrase
# xxd -p -c 32 /root/.passphrase
25ff3c06493f809e8d9639040e1d7e093960860e07631d71388509af12b561c3

Now, let's add the new passphrase to our device (you will be prompted for known passphrase to enter):

# cryptsetup luksAddKey /dev/rootvg/home /root/.passphrase
Enter any existing passphrase:
# cryptsetup luksDump /dev/rootvg/home

You will see Key Slot 1 will be in use now. Let's check the new functionality:

# umount /dev/mapper/home 
# cryptsetup luksClose home
# cryptsetup luksOpen /dev/rootvg/home home --key-file /root/.passphrase

Once manual activation is works, let's change /etc/crypttab file:

# cat /etc/crypttab
# name device passphrasefile options
#home /dev/rootvg/home none luks,x-systemd.device-timeout=0
home /dev/rootvg/home /root/.passphrase luks
And reboot the system.

Resizing encrypted FS

Expanding FS

The following steps should be performed:

  1. Increasing physical device (LV in our case)
  2. Increasing encrypted device
  3. Increasing FS
# pvs
  PV         VG     Fmt  Attr PSize PFree
  /dev/vda2  rootvg lvm2 a--  9.75g 3.50g
# lvs
  LV    VG     Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  home  rootvg -wi-ao---- 256.00m
  slash rootvg -wi-ao----   3.00g                                                    
  swap  rootvg -wi-ao----   1.00g                                                    
  var   rootvg -wi-ao----   2.00g                                                    
# lvresize -L+1g /dev/rootvg/home
  Size of logical volume rootvg/home changed from 256.00 MiB (64 extents) to 1.25 GiB (320 extents).
  Logical volume rootvg/home successfully resized.
# cryptsetup resize /dev/mapper/home
# resize2fs /dev/mapper/home 
resize2fs 1.43.3 (04-Sep-2016)
Filesystem at /dev/mapper/home is mounted on /home; on-line resizing required
old_desc_blocks = 2, new_desc_blocks = 10
The filesystem on /dev/mapper/home is now 1308672 (1k) blocks long.

# df /home
Filesystem        Size  Used Avail Use% Mounted on
/dev/mapper/home  1.3G  2.7M  1.2G   1% /home

Shrinking FS

The steps are opposite and requires exact sizing values:

  1. Shrinking FS. Make it less than desired size, exact size will not fit.
  2. Reducing encrypted device
  3. Reducing underlying physical device (LV in our case).
# umount /dev/mapper/home
# resize2fs /dev/mapper/home 1000m
resize2fs 1.43.3 (04-Sep-2016)
Please run 'e2fsck -f /dev/mapper/home' first.

# e2fsck -f /dev/mapper/home
e2fsck 1.43.3 (04-Sep-2016)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/home: 11/325120 files (0.0% non-contiguous), 47921/1308672 blocks
# resize2fs /dev/mapper/home 1000m
resize2fs 1.43.3 (04-Sep-2016)
Resizing the filesystem on /dev/mapper/home to 1024000 (1k) blocks.
The filesystem on /dev/mapper/home is now 1024000 (1k) blocks long.
# cryptsetup status /dev/mapper/home
/dev/mapper/home is active.
  type:    LUKS1
  cipher:  aes-xts-plain64
  keysize: 256 bits
  device:  /dev/mapper/rootvg-home
  offset:  4096 sectors
  size:    2617344 sectors
  mode:    read/write
# echo $((1*1024*1024*2)) # <-- 1G in 512b sectors
2097152
# cryptsetup resize /dev/mapper/home --size 2097152
# cryptsetup status /dev/mapper/home
/dev/mapper/home is active.
  type:    LUKS1
  cipher:  aes-xts-plain64
  keysize: 256 bits
  device:  /dev/mapper/rootvg-home
  offset:  4096 sectors
  size:    2097152 sectors
  mode:    read/write
# lvresize -L1g /dev/rootvg/home
  WARNING: Reducing active and open logical volume to 1.00 GiB.
  THIS MAY DESTROY YOUR DATA (filesystem etc.)
Do you really want to reduce rootvg/home? [y/n]: y
  Size of logical volume rootvg/home changed from 1.25 GiB (320 extents) to 1.00 GiB (256 extents).
  Logical volume rootvg/home successfully resized.
# resize2fs /dev/mapper/home
resize2fs 1.43.3 (04-Sep-2016)
Resizing the filesystem on /dev/mapper/home to 1046528 (1k) blocks.
The filesystem on /dev/mapper/home is now 1046528 (1k) blocks long.

Recovery encrypted volumes

You should have saved master key somewhere in secure place to be able recovery forgotten passphrases. So, dump it and save:

# cryptsetup luksDump --dump-master-key  /dev/rootvg/home

WARNING!
========
Header dump with volume key is sensitive information
which allows access to encrypted partition without passphrase.
This dump should be always stored encrypted on safe place.

Are you sure? (Type uppercase yes): YES
Enter passphrase: 
LUKS header information for /dev/rootvg/home
Cipher name:    aes
Cipher mode:    xts-plain64
Payload offset: 4096
UUID:           f520b10c-6ea8-4565-aa82-7a382bc952c4
MK bits:        256
MK dump:        00 0f 05 0d 2a bb 78 a0 43 86 6d b0 44 3a 2c d5 
                bd 70 5c be 33 1c e5 1f 38 7c f8 cd 63 50 9f 2f

The other way to see master key for already opened device without need to enter passphrase:

# dmsetup table --showkeys | grep ^home
home: 0 2097152 crypt aes-xts-plain64 000f050d2abb78a043866db0443a2cd5bd705cbe331ce51f387cf8cd63509f2f 0 253:3 4096

As you see it is the same key as MK dump: value. Translate it into binary form:

# echo 000f050d2abb78a043866db0443a2cd5bd705cbe331ce51f387cf8cd63509f2f | xxd -r -p > MK.bin
# xxd -p -c 32 MK.bin 
000f050d2abb78a043866db0443a2cd5bd705cbe331ce51f387cf8cd63509f2f

Now you can add a new passphrase without knowing the previous:

# cryptsetup luksAddKey /dev/rootvg/home --master-key-file MK.bin 
Enter new passphrase for key slot: 
Verify passphrase: 
# cryptsetup luksDump /dev/rootvg/home

Updated on Fri May 19 23:46:26 IDT 2017 More documentations here