One tricky part of mirroring your highly customized Linux system (with a distro like archlinux) to a new machine is the gpg-related stuff. For example, I use pass as my password manager, which uses a gpg key to encrypt/decrypt your passwords. Properly migrating this setup to a new machine turned out to be quite a chore. But here is how I did it.

Setup on the old-machine

Here is what I have on the old-machine:

  • A gpg key pair (let’s call it with a fake key id 0xFFFFFFFF) that was used to initialize and encrypt the password-store;
  • A remote git repo that backs up all the passwords.

This means the password-store was originally set up as follows:

$ pass init 0xFFFFFFFF --path ~/.local/share
$ pass git init
$ pass git remote add origin https://url/to/your/repo.git

Now you can generate, modify and organize passwords using pass commands and store them under ~/.local/share with a simple structure. I would also sync with the remote repo whenever there is a change. For this, good news is that pass automatically stages and commits changes (with an auto-generated descriptive message) so all you need to do is a push command.

$ pass git push origin master

Transfer you gpg keys

We use the following gpg command to export the key to a file:

$ gpg -a --export-secret-keys 0xFFFFFFFF > my-sec-gpg.key

The -a flag turns on ASCII armoring which is a printable format of the key to help you back it up. If you open the file, you will see those “random” ASCII characters. Note that to actually extract the private key information from this file, the passphrase (originally used to construct the key pair) is still required. In other words, the file my-sec-gpg.key is still encrypted and the level of security depends on the strength of your passphrase. Choose a very strong passphrase always; write it down somewhere instead of storing it in your computer.

For our purpose, we don’t need to export the public key since it’s embedded in my-sec-gpg.key.

Finally, after copying this key file to an encrypted device (see next section), we should wipe the file like this (using rm is not secure):

$ shred -vu my-sec-gpg.key

This archwiki page has very useful information on securely wiping disks.

Next up, we transfer the key file using an encrypted USB stick to the new-machine.

Make an encrypted USB stick

A brief guide on how to encrypt a USB stick is in order. We will use the LUKS (Linux Unified Key Setup) format. A detailed documentation can be found at this archwiki page.

We need:

  • A USB stick, obviously. BACK UP YOUR DATA since it’s gonna get erased.
  • The kernel module dm_crypt. This module does the encryption and to load it (in case it’s not):
    $ modprobe dm_crypt
    
  • A program called cryptsetup. This program provides a userland interface for dm-crypt. If you are running arch, it should be already installed as a dependency of systemd.

Now plug in the USB stick. I pre-wiped its data with dd and created a single partition using the whole space with fdisk. My machine reads it as /dev/sdb1. I’ll use a fake identifier /dev/sdbX in the following.

To encrypt this partition, do

sudo cryptsetup luksFormat /dev/sdbX

When successful, run

sudo cryptsetup luksFormat /dev/sdbX

You should see a screenful of information - the LUKS header information. These are the unencrypted part of the device that contains metadata of the encryption (cipher, keyslots, hash values, etc.).

The usual mounting command goes like sudo mount /dev/sdXY /mnt where /dev/sdXY is the address of the device and /mnt is the specified mount point. To mount the newly encrypted device, however, we need the following extra steps. First, we need to set a password to the encrypted device:

sudo cryptsetup open /dev/sdbX usb

This will prompt you to enter a password. Make it strong and write it down somewhere safe to back up. The last parameter, usb, is the name assigned to the device, usually descriptive of its function, hence usb in our case. After this, a new address, /dev/mapper/usb, is created for the partition. And this will be the address we use to mount the device.

$ lsblk
NAME    MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
...
sdd       8:48   1  28.8G  0 disk
└─sdd1    8:49   1  28.8G  0 part
  └─usb 254:0    0  28.8G  0 crypt

Now you can mount it:

$ sudo mount /dev/mapper/usb /mnt
$ lsblk
NAME    MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
...
sdd       8:48   1  28.8G  0 disk
└─sdd1    8:49   1  28.8G  0 part
  └─usb 254:0    0  28.8G  0 crypt /mnt

Copy the key file. When successful, shred the key:

$ cp my-sec-gpg.key /mnt
$ shred -vu my-sec-gpg.key

Now unmount the device and close the device mapper:

$ sudo umount /mnt
$ sudo cryptsetup close usb

Onto the new-machine

If you have read this far, you know what you are gonna do on the new-machine: (1) plug in the USB stick, (2) open the LUKS container (you will be prompted for the password you set), (3) mount the encrypted device, (4) make a copy of the secret key file to the new-machine.

Then, import the key:

$ gpg --import my-sec-key.gpg
$ # when successful...
$ shred -vu my-sec-gpg.key

After importing the key you created the password-store with in the old-machine, repeat the steps to set it up on the new-machine:

$ pass init 0xFFFFFFFF --path ~/.local/share
$ pass git init
$ pass git remote add origin https://url/to/your/repo.git

If you make a git-pull now, there will be a merge conflict error. This is because the pass git init command automatically makes a couple of local commits upon initiation, which are not part of the remote master branch (which has the initiation commits from the old-machine). So back up your local branch and pull and move to the repo master branch:

$ pass git fetch --all
$ pass git branch backup-branch
$ pass git reset --hard origin/master

You can now decrypt and access your passwords using the imported secret key.

Job not done though! To generate and renew passwords, you would need encryption with the public key. We have the public key in the new-machine, but we still need to validate it. This is a cruicial step in public-key cryptography since public keys, due to being public, are prone to tampering. Validation is the step where you affirm their ownership. We do this within gpg’s console-mode:

$ gpg --edit-key 0xFFFFFFFF
gpg (GnuPG) 2.4.5; Copyright (C) 2024 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
...
(personal key info omitted)
...

gpg> trust

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision?

5

Job done! Now your have your familiar password management environment on the new-machine.

As a final word, here are some nice tools/extensions I use on top of pass:

  • passmenu: access your password-store with the suckless menu tool dmenu;
  • pass-update: generate and replace passwords with an easy flow.