Creating a Horcrux-style system for your encrypted backups

2023-03-26

See all posts

In this post, I will guide you on how to safely store encrypted backups of your data by using a system that involves protecting data with multiple hardware security keys.

SSS vs. WTF is a Horcrux

You can set up a system that either requires all keys (or a subset of them) to be required for decryption or set it up in a way that as long as one key is available, users can recover their encrypted data. Both cases are based on the idea of splitting a secret into multiple parts and storing each part in a different location.

Shamir's Secret Sharing (SSS) can be used to set up the first option. The second option, which I call a "digital Horcrux," is inspired by the Harry Potter series. In the books, wizards store parts of their souls in magical objects called Horcruxes. As long as one of these objects exists, the wizard cannot be defeated or killed. In the context of encrypting data, we can set up Horcruxes digitally. However, in this post, I will describe a setup where all Horcruxes are stored exclusively on hardware security keys. The benefit of this setup is that the keys can be safely stored or hidden in the real world, and the secret keys cannot be easily extracted by an adversary.

Horcrux

Sounds cool, right? Let's adapt this idea to encrypting data. While you can set up Horcruxes purely digital, I will describe a setup where all Horcruxes are exclusively stored on hardware security keys. This is because those can be safely stored (or hidden) in the real world, and the secret keys cannot be easily extracted by an adversary.

Setup

To achieve this setup, you need the following three ingredients:

  1. One or more YubiKey / Trezor devices as hardware security keys
  2. age by Filippo
  3. age-plugin-yubikey by str4d / age-plugin-trezor by romanz

Initial Configuration

Before we begin, we first need to create list of identities and recipients. Each identity is bound to a specific slot in your YubiKey's PIV slots. A recipient is an age-compatible public key that we can use to encrypt data with. For decryption, we call age -i <identity> -d <ciphertext.age> to decrypt the ciphertext with the secret key, that stays protected on the hardware security key.

Example:

You can get a new identity and recipient from a new YubiKey by running:

age-plugin-yubikey --generate

This will guide you through key / identity generation. It's fine to accept the defaults.

If you are using a Trezor device, run:

age-plugin-trezor -i "John Doe" | tee identity

Both commands will print both the recipient address (public key) and the identity to stdout. Please remember that the identity string is not your secret key. The secret keys will never be exposed from your hardware security key to your host.

You can list previously generated device recipients at any time by running

age-plugin-yubikey --list
#       Serial: 12345678, Slot: 1
#         Name: age identity 12345678
#      Created: Thu, 01 Jan 2023 13:37:69 +0000
#   PIN policy: Once   (A PIN is required once per session, if set)
# Touch policy: Always (A physical touch is required for every decryption)
age1yubikey1qkfhgdkhgdlkghdsl6ghsgs3hkgsdk4ghd4skghsdk9ghsdklghsldkghkd

or to list your identity:

age-plugin-yubikey --identity
#       Serial: 12345678, Slot: 1
#         Name: age identity 12345678
#      Created: Thu, 01 Jan 2023 13:37:69 +0000
#   PIN policy: Once   (A PIN is required once per session, if set)
# Touch policy: Always (A physical touch is required for every decryption)
# Recipient: age1yubikey1qkfhgdkhgdlkghdsl6ghsgs3hkgsdk4ghd4skghsdk9ghsdklghsldkghkd
AGE-PLUGIN-YUBIKEY-1LXDKGH577SKHJ5SKH2GHC

We want to keep track of this info, so we encrypt to recipients without having the security keys plugged in all the time. For that, let's create a directory ~/.age in your home directory for managing them:

mkdir ~/.age
age-plugin-yubikey --list >> ~/.age/recipients
age-plugin-yubikey --identity >> /.age/identities

Notice that we are appending to those files. Why?

Well... because we want to encrypt data to multiple recipients at once. Or, in other words, we want to be able to decrypt data as long as one YubiKey is available to us. Horcruxes, remember? ;)

Seeing it in action

We are now able to securely encrypt data at any time to all identities that are stored in our ~/.age/recipients file like this:

age -e -R ~/.age/recipients secret.txt > secret.txt.age

This will create an encrypted file secret.txt.age that can be decrypted only when at least one of the YubiKeys is plugged in!

How? Let's run

age -d -i ~/.age/identities secret.age.txt > secret.txt

to restore the original file from the encrypted ciphertext.

You can now combine this with tar, zip, rsync, whatever you like to create encrypted files and backups that can only be decrypted with one of your security key identities. Cool, right?

Adding / removing Horcruxes

Fortunately, we can split and re-key as often and as much as we like without killing someone like Voldemort did.

We just need to update the ~/.age/ files and run a little re-keying scrypt, where we decrypt the ciphertexts with one of the old identities and re-encrypt it to the updated recipients file. Same goes for removing recipients.

Caveats

Remember that you cannot "clone" the identity of a YubiKey (you may with a Trezor) so make sure that you perform a re-keying of your encrypted data with an updated .age-recipients file once you change your setup or you remove/add a Horcrux.

Consequently, if all Horcruxes get lost or destroyedbroken, you will lose all access to decrypting your data.

Voldemort turns to dust

More like this

If you like this concept you can check out more resources to this topic: