Welcome to this easy follow along guide on how to secure your online identity if you
- own at least two hardware security keys/tokens (e.g. YubiKeys)
- are paranoid
- have a funny understanding of easy
Usually the recommended way of using hardware security keys/tokens, such as YubiKeys, is to have at least two security keys, and register all of them with the online-services you use (Google, GitHub, ...). In case you loose one, you still have a second one.
Also, you usually get recovery/backup codes from these services to disable 2FA in case you loose all security keys, which you are supposed to print out.
There are a couple of points bothering me with this approach
- You have a single point of failure. If your house burns down, all your security keys and the recovery codes might be lost. You are locked out forever from everything
- I don't want to print the recovery codes (annoying). If I store them in my password manager instead, the password manager contains the login credentials and information to disable 2FA, which basically circumvents the purpose of security keys, and we have created another single point of failure – compromising the password manager
- I would like to have multiple secrets that I can split between trustees. Collecting all those secrets allows to restore and access everything – computer, backups, password manager, recovery codes – even if I die in the fire which burns down the house, security keys and physical backups
I also had two additional requirements
- I don't want all secrets lying around at my place. If someone robs my house and takes everything, he/she should not possess everything necessary to unlock my digital life
- Usage should not suck
The idea is to have two separate password managers/vaults:
One is the daily used one, which stores the credentials to online services and other stuff often needed. It does not store 2FA recovery codes or anything "critical". Compromising this one is definitely not desirable, but also not fatal.
The second vault is the locked down, rarely accessed, rarely changed one, containing only crucial information. The cold vault.
This one is used if we are locked out of the daily vault, the house burned down, the security keys are lost, something happened to me, etc.
It contains everything to access the daily vault and disable the security keys. I'll refer to this one as the bootstrap-vault. Having access to this one gives access to everything.
This one is secured through two factors – a password and a security key. Keepass for example can use security keys as additional factor.
We also split the security keys in two groups: The daily one(s) and a bootstrap one.
The bootstrap one can unlock the bootstrap-vault.
The daily ones are the ones that are used... daily. We register them with all the services we use. They are also able to unlock the bootstrap-vault, so we don't only rely on the bootstrap security key to unlock the bootstrap-vault.
This gives us three secrets to access the information in the bootstrap-vault: Its password, a security key and the Keepass file itself. These secrets can be given to others we trust, and who hopefully don't conspire.
This leaves us with one problem: We will get new 2FA recovery codes everytime we register with a new service. We cannot store them in the daily-vault, as they cannot go there for security reasons. We also cannot store them in the bootstrap-vault, as we cannot change the file after giving it to trustees.
Therefore, we encrypt them asymmetrically. We generate a pgp key and keep the private key only in the bootstrap-vault. The public key remains on our computer, and whenever we register our security keys with a new service, we encrypt the recovery codes and store the ciphertext in our daily-vault.
For convenience, I am using the same password for the bootstrap- and daily-vault. The bootstrap-vault is not kept on my hard-drive, therefore I don't see a huge security benefit in having different passwords for them.
This leaves us with following constellation:
Secrets: Password, any security key and possession of vault-file
- All information/secrets how to access daily-vault
- PGP private key to decrypt 2FA recovery codes stored in daily-vault
- The secret necessary to create more security keys which can unlock the bootstrap-vault
- Regular credentials to log into services
- everything else "uncritical"
As daily-vault I am using one which is synced to a cloud, so I cannot lose it. If your daily-vault is not synced, you must be able to access your backups containing your daily-vault, using the information in the bootstrap-vault.
Therefore, in that case remember to add the information necessary to access and decrypt your backups to the bootstrap-vault.
Is this usable? I'd say yes!
Setup takes an afternoon, but after this, the only difference to the "recommended" approach is that we pgp encrypt the recovery codes instead of printing them. I actually prefer that.
What to do
Configure Security Keys for challenge-response mode
We configure all security keys with the challenge-response mode, so all keys can be used to unlock the bootstrap-vault.
# first key, let ykman generate secret key, configure in slot 2
ykman otp chalresp -g -t 2
# all other keys, program with same secret key
ykman otp chalresp -t 2 <SECRET KEY>
Generate PGP Key to encrypt 2FA backup/recovery codes
Generate a PGP Key which will be used to encrypt the recovery codes that are used to disable 2FA if all daily security keys are lost. Make up some email address, it does not need to exist.
gpg --armor --export-secret-keys <EMAIL> > 2fa-recovery-codes-private-key.asc
gpg --armor --export <EMAIL> > 2fa-recovery-codes-public-key.asc
2. Create Bootstrap-Vault
Download a Keepass variant which supports the challenge-response mode of security keys (e.g. KeePassXC on macOS). Create a new vault/password-database with security key challenge-response as additional factor.
Verify that all security keys are able to unlock the vault.
Add the following required content to the vault:
- The secret key which is used to program the challenge-response mode on the security keys. This is necessary, so we have the option to add more security keys in the future, which are able to unlock the bootstrap vault
- Everything necessary to unlock the daily-vault
2fa-recovery-codes-private-key.ascprivate key and its passphrase. This is important so 2FA can be disabled on all services in case all daily security keys have been lost
2fa-recovery-codes-public-key.ascpublic key, just as a backup
Optionally we can add more things, which can be useful to cut corners or which are so sensible and rarely used, that we don't want them in the daily-vault, e.g.
- iCloud password/iCloud Account Recovery Key in plaintext (instead of storing pgp encrypted in daily-vault)
- macOS password
- TimeMachine password
- How to access and decrypt remote backup
- SSH Key
2fa-recovery-codes-private-key.asc private key from your filesystem and from the gpg keyring, as it is now stored in the bootstrap-vault.
gpg --delete-secret-keys <EMAIL>
Try to restore and unlock the bootstrap-vault, only using the three secrets, ideally on a different computer, so you cannot accidentally access anything which you usually shouldn't have. See details at
Recovery procedure about the process. Don't forget to test decoding the QR code if you are storing the bootstrap-vault as QR code (see step 4).
4. Distribute secrets
We now have three secrets, the bootstrap security key, the password to unlock the bootstrap-vault and the bootstrap-vault itself.
To distribute the bootstrap-vault we have a couple of options, e.g.:
- Burn it to a CD
- Store it on a thumb drive/external hard-disk. Be aware that flash storage usually looses its data after months to a few years
- The bootstrap-vault is very small. Therefore, and for geeky reasons, we can convert it to QR codes and print them
Methods one and two should be trivial, so here is how to create the QR codes: The largest QR code (v 40) at error correction level medium can hold 2331 bytes, therefore we need to split the vault into multiple chunks and generate multiple qr codes.
# create chunks
cat bootstrap-vault.kdbx | split -b 2331 -d - chunks/chunk-
# create a qr code for each chunk
ls chunks/chunk-* | xargs -I %chunkfile sh -c 'cat %chunkfile | qrencode --8bit -v 40 --level=m -t SVG --output %chunkfile.svg'
Optionally, we can also create a signature/checksum of the vault and store it on the cd/thumb drive
# Bonus, create checksum/signature of vault
sha1sum bootstrap-vault.kdbx > bootstrap-vault.kdbx.sha1
gpg -b -a -u <EMAIL> bootstrap-vault.kdbx
Now we can distribute our secrets:
We have to make sure that there are always two copies of each secret, and they are never in the same location. Here is what I do
- Boostrap vault: 2 sets of QR-code-printouts/CDs, one in my documents, one given to a person I trust
- Password to unlock the vault: Given as printout to a different trustee + stored in my head
- Security keys: All keys are programmed to unlock the bootstrap-vault. The bootstrap one is given to a trustee, I keep the daily ones. You shouldn't visit this trustee with all other security keys
Verify the information stored in the daily-vault: This is the vault which is in daily use and will often be unlocked. This should be of limited usage if it got somehow compromised.
It should contain
- Logins to services + the pgp encrypted recovery codes to disable the security keys/2FA on those services
- Information on how to access the remote backup/local backup, regardless of whether it is already stored in the bootstrap-vault. We need this information regularly when doing backups
- The optional stuff from the bootstrap vault. In case it changes, we don't need to immediately distribute a new version of the bootstrap-vault to the trustee
It should not contain the required stuff from the bootstrap-vault!
Start registering the daily security keys on all services. Save the recovery codes pgp encrypted in the daily-vault:
gpg --encrypt --armor -r <EMAIL> recovery-codes.txt
- Remove other 2FA methods from services
- Delete files on your hard drive, which are stored in one of the vaults. E.g. the private pgp key (if you haven't yet)
- Delete the bootstrap-vault from your hard drive
Beedoo-beedoo 🚨🚨, disaster struck. How to restore?
Gather the three secrets (bootstrap-vault, vault-password, any security key).
If you are restoring from the QR codes, take a picture of them. In my tests
zbarimg was pretty picky regarding the images. I had to use Photoshops perspective crop tool to make them near perfect squares and use image -> adjustments -> threshold to convert it to black/white. Place the prepared pictures in a
qrcodes folder. Make sure their filenames are correctly ordered, as we need to append them in the correct order.
ls qrcodes/*.png | xargs -I %img sh -c 'zbarimg --raw %img > %img.bin'
ls qrcodes/*.png.bin | sort | xargs cat > restored-bootstrap-vault.kdbx
If you have the checksum file or pgp signature file, you can verify them:
sha1sum -c bootstrap-vault.kdbx.sha1
gpg --verify bootstrap-vault.kdbx.asc
Open the bootstrap-vault using the password and security key.
In the bootstrap-vault, find information on how to access the daily-vault.
In the daily-vault, find information on how to restore files from backup, access computer, anything else. Decrypt recovery codes if you want to disable 2FA
gpg --import 2fa-recovery-codes-private-key.asc
gpg --decrypt recovery-codes.txt.asc