2023-03-26
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.
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.
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.
To achieve this setup, you need the following three ingredients:
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? ;)
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?
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.
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.
If you like this concept you can check out more resources to this topic: