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
.
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:
gocryptfs
rsync
, rclone
, or something else).My environment in this post is GNU/Linux, Ubuntu 22.04.
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
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