newline

Table of Contents

  1. Intro
  2. Basic usage of gocryptfs for a backup
  3. Encrypting/decrypting paths

File-based encryption with gocryptfs

Shell

November 15, 2024

Here’s the problem for today: I can back up my files to cloud storage, but I don’t want to back them up as-is – I want to encrypt them. Also, I only want to encrypt and back up a selection of my home directory. I don’t want to have to do a backup of the full thing every time, I want something more incremental, at the file/directory level. Therefore, I need file-based encryption: a system that encrypts individual files, preserving the directory structure. We can do that with gocryptfs.

Intro

gocryptfs is an ‘overlay’ filesystem, written in Go, and using the FUSE library. Basically it lets you mount an encrypted directory as a plaintext directory (‘forward’ mode, the default), or you can mount a plaintext directory as an encrypted directory (‘reverse’ mode). It has some limitations, but is enough for general use.

To create a backup of your home directory, the steps would be:

  1. Mount your home directory as an encrypted directory with gocryptfs
  2. Synchronize the encrypted directory with cloud storage (e.g. with rsync, rclone, or something else).

My environment in this post is GNU/Linux, Ubuntu 22.04.

Basic usage of gocryptfs for a backup

After installing gocryptfs according to the instructions, the next step is to initialize gocryptfs for the directory we want to back up (the home directory):

gocryptfs -init -reverse /home/me

The -reverse means we want to create an encrypted mount from a plaintext directory.

It’ll ask you for a password; save that and the master key in a secure place. The command created a file at /home/me/.gocryptfs.reverse.conf, which contains information about the encryption.

Next, we want to select what to back up. For this example, we only want to back up a password store at /home/me/Documents/password-store. Create a file ~/.gocryptfs-exclude (naming is arbitrary):

# Exclude everything
*
# Include ~/Documents
!/Documents
# Exclude all in ~/Documents
/Documents/*
# Include ~/Documents/password-store
!/Documents/password-store

As per man gocryptfs, the file uses gitignore syntax, so we have to do a bit of an exclude-include dance in the file. The root path refers to whatever path we’re encrypting, so / in the exclude file refers to /home/me. If you don’t use a strong password, you may want to also exclude the /home/me/.gocryptfs.reverse.conf.

Then, we create a mountpoint:

sudo mkdir /mnt/encrypted
# Take ownership so we don't have to sudo anymore
sudo chown -R `whoami`:`whoami` /mnt/encrypted

And start gocryptfs:

gocryptfs -reverse -exclude-from /home/me/.gocryptfs-exclude /home/me /mnt/encrypted

It’ll ask you to enter your password, and when you do, you should find that /mnt/encrypted contains a directory tree with gocryptfs.diriv and files/directories with some random characters. That’s your original file tree, but with file names and content encrypted through gocryptfs.

Now you can copy whatever files you need. When you’re done, unmount the gocryptfs file tree with:

umount /mnt/encrypted

Encrypting/decrypting paths

As you saw, the filenames are all encrypted. However, you’d still like to know what they refer to. For that, you can use gocryptfs-xray, included with the gocryptfs installation, which lets you encrypt/decrypt file paths.

First, you need to instruct gocryptfs to create a control socket:

gocryptfs -reverse -ctlsock /run/user/"$(id -u)"/gocryptfssock -exclude-from /home/me/.gocryptfs-exclude /home/me /mnt/encrypted

Note the extra ctlsock option to create the control socket. The location is arbitrary, though it should not be world-accessible.

Then, you can use gocryptfs-xray:

# Encrypt path names from stdin
gocryptfs-xray -encrypt-paths /run/user/"$(id -u)"/gocryptfssock

# Decrypt path names from stdin
gocryptfs-xray -decrypt-paths /run/user/"$(id -u)"/gocryptfssock

Both invocations will wait for input, because they read from standard input, so you can copy-paste path names in, and press the enter key to get encrypted/decrypted output (or you can pipe some filenames in). The path names are relative to the root of the encrypted file tree (/home/me or /mnt/encrypted in this case).

For example, a one-liner to get all decrypted file paths:

find /mnt/encrypted -type f -not -name 'gocryptfs.diriv' \
    | cut -d/ -f4- \
    | gocryptfs-xray -decrypt-paths /run/user/"$(id -u)"/gocryptfssock