Filesystem-based encryption with PEFS
NOTE: the author/maintainer of the tutorial(s) is no longer with the show, so the information below may be outdated or incorrect.
In the day and age we live in, it seems security and privacy have been thrust into the forefront of the computing world. More than ever, users and companies are trying to find ways to keep their private data private. Encryption has always been a good choice and there are a number of utilities to use, some commercial and some open-source, some kernel level and some userland. On FreeBSD, most users have been using the kernel-level "GELI" framework, usually for low-level disk encryption. Typically this would sit "underneath" the user's file-system, such as UFS or ZFS. However, this may be less than optimal in a few situations, such as wanting to encrypt only a single directory or wanting to replicate ZFS snapshots which sit on top of the GELI layer. Enter the PEFS framework. PEFS, which stands for Private Encrypted File System, is a kernel-level stacked cryptographic filesystem for FreeBSD.
One of the main differences between GELI and PEFS is that, while GELI sits below your filesystem encrypting blocks of data before it hits the disk, PEFS will sit on top, encrypting files and directories before they hit the underlying filesystem. This allows PEFS to run on the top of ZFS, which can be a benefit when wanting to replicate encrypted data using ZFS send/receive functionality. In addition, PEFS also comes bundled with a PAM module, allowing for entire home directories to be encrypted and decrypted based upon the user logging into the system, which can be very beneficial to multi-user workstations. In today’s tutorial we will be taking a look at how to install and create PEFS-encrypted directories, as well as enabling PAM logins for PEFS home directory encryption.
# cd /usr/ports/sysutils/pefs-kmod # make install clean
# pkg install pefs-kmod
Once installed, we next need to load the pefs kernel module:
# kldload pefs
If we want to keep this module loaded across reboots, add it to /boot/loader.conf:
# echo 'pefs_load="YES"' >> /boot/loader.conf
To create our first encrypted directory, we will begin with creating two new dirs:
# mkdir ~/encrypted ~/unencrypted
By default PEFS does not store any meta-data related to your keys on disk, and as such has no way to verify the correctness of the key entered. However, to achieve this functionality, PEFS does have support for keychains. A single key can be used to replicate traditional key storage.
Next we will add a single parent key to our encrypted directory.
# pefs addchain -f -Z ~/encrypted Enter parent key passphrase: Reenter parent key passphrase:
The -Z flag is used to specify that this keychain will consist of only a single parent key, no children. The -f flag will skip checking the underlying filesystem to see if it is already encrypted. Next, we will mount the pefs filesystem. Note that this does not require the encryption key, that will come later.
# pefs mount ~/encrypted ~/unencrypted
Note at this point that the ~/unencrypted file-system only contains the single .pefs.db file (for the keychain), and is mounted read-only. To decrypt the directory, we will next add our key:
# pefs addkey -c ~/unencrypted Enter passphrase:
The -c flag is used to "check" the key supplied against the keychain database, and reject a mis-typed or bad key. Now the ~/unencrypted directory should be mounted r/w and we can begin adding our private data.
# echo "testing" > ~/unencrypted/test.txt # ls ~/unencrypted/ .pefs.db test.txt # cat ~/unencrypted/test.txt testing # ls ~/encrypted/ .7ve2p00YVmMBFLlAzJ0k+BC85G67t4KT .pefs.db # cat ~/encrypted/.7ve2p00YVmMBFLlAzJ0k+BC85G67t4KT <garbage>
Now we can just as easily remove our key and re-encrypt the ~/unencrypted directory:
# pefs flushkeys ~/unencrypted # ls ~/unencrypted .7ve2p00YVmMBFLlAzJ0k+BC85G67t4KT .pefs.db
Note that for this tutorial we used both ~/encrypted and ~/unencrypted directories. It is possible to have all this done on a single "~/encrypted" directory, simply by replacing ~/unencrypted with ~/encrypted in the commands run. Next, we will take a look at how we can use PEFS to create an encrypted home directory.
To get started, if this is an existing user, we will want to move their files out of their home directory:
# mv /usr/home/test /usr/home/test.old # mkdir /usr/home/test # chown test:test /usr/home/test # pefs addchain -f -Z /usr/home/test # pefs mount /usr/home/test /usr/home/test
Enter your username password.
# pefs addkey /usr/home/test
Enter your user's password. Next move out the .pefs.db file
# mv /usr/home/test/.pefs.db /tmp/.pefs.db
Copy data back into the encrypted filesystem.
# tar cvf - -C /usr/home/test.old . | tar xvf - -C /usr/home/test
# umount /usr/home/test
Copy database file back.
# mv /tmp/.pefs.db /usr/home/test/ # chown test:test /usr/home/test/.pefs.db
# pefs mount /usr/home/test /usr/home/test
If your /home directory is a symlink to /usr/home, you may need to adjust the passwd file. PEFS will not work on symlinks, run "vipw" and adjust your users home dir to the real path.
Lastly we need to add the PAM module to our login process.
--- system 2013-08-26 09:39:18.014375012 -0400 +++ system 2014-02-25 09:36:57.141849155 -0500 @@ -9,6 +9,7 @@ auth requisite pam_opieaccess.so no_warn allow_local #auth sufficient pam_krb5.so no_warn try_first_pass #auth sufficient pam_ssh.so no_warn try_first_pass +auth sufficient pam_pefs.so try_first_pass delkeys auth required pam_unix.so no_warn try_first_pass nullok # account @@ -18,6 +19,7 @@ # session #session optional pam_ssh.so want_agent +session optional pam_pefs.so delkeys session required pam_lastlog.so no_fail # password
Now we should be able to open a fresh login with the "test" user, and the home-directory will be automatically decrypted upon login, and re-encrypted at logout.
PEFS also supports more advanced keychain functionality, such as escalating privledge and such (which are outside the scope of this tutorial today). For reference, take a look at the manpage or the wiki.