Gratifying vanity with vanity keys

I found out about the Nostr social network a couple months ago. The network is based on public key cryptography. While browsing the feeds, I noticed some people had really nice public keys which contained their username in some form, like Snowden’s npub1sn0wdenkukak0d9dfczzeacvhkrgz92ak56egt7vdgzn8pv2wfqqhrjdv9. My key is still being generated, since my username is quite a mouthful.

So I wondered if GPG keys can be generated like this too. And of course, they can.

Improving my PKI

While I’m at it I may as well upgrade my public key infrastructure to use EC cryptography which has become more widely supported in recent years, especially by software like gnupg and openssh.

The plan is as follows:

  • mine a nice ed25519 vanity masterkey
  • mine vanity subkeys for signing, encryption (cv25519) and authentication
  • import my old gpg RSA key as subkey - my previous password manager used it plus I sent a couple e-mails and commits with this key, so I’ll try to keep it in my keyring instead of archiving and forgetting about it
  • upload keys to keyservers - I’ll run my own as well
  • replace my mess of ssh (rsa and dsa) keys with just ed25519 keys as all of my systems support it anyway

There will be some trickery required to get the vanity public keys under the vanity master, like time travel and key forgery.

Importing generated vanity keys as subkeys

Luckily GPG has made this somewhat easy lately, one just has to be careful not to mess things up.

  1. use some vanity key generator to “mine” your keys, I used https://github.com/cuihaoleo/gpg-fingerprint-filter-gpu. On my GTX 1080 TI, mining a 12-character key would take less than a day.
  2. import the generated keys into gpg (these don’t have uids yet): $ gpg --allow-non-selfsigned-uid --import /path/to/your/key.gpg
  3. look up the keygrip of the key you are adding as subkey: $ gpg --list-keys --with-keygrip
  4. look up the creation time of the subkey in unix timestamp format: $ gpg --list-keys --with-colons You’ll get an output like:
tru::1:1685629907:0:3:1:5
pub:i:255:22:10EF73ED9C05C0DE:1670154005:::-:::sca:::::ed25519:::0:
fpr:::::::::5D9EC206356B4CD2DC03F18C10EF73ED9C05C0DE:
uid:-::::::1E23F740019D67CEA575A8B356807D296C2D0536::NONAME::::::::::0:
pub:i:255:22:06D688AC552AC0DE:1685617802:::-:::sca:::::ed25519:::0:
fpr:::::::::179E198C2B21D93DF22AD9C906D688AC552AC0DE:
uid:-::::::1E23F740019D67CEA575A8B356807D296C2D0536::NONAME::::::::::0:

Decide which key to use as masterkey and which keys will be its subkeys. Each key begins with pub:, the unix timestamp is in the 6th column - it starts with 16.. at the time of writing, it’s easy to spot if you work with unix timestamps a lot.

  1. edit the masterkey with fake time - the exlamation mark in the faked-system-time is important as it freezes this fake time throughout the gpg’s session: $ gpg --expert --faked-system-time=1685617802\! --ignore-time-conflict --edit-key <your master key>

  2. in gpg’s prompt, run addkey, then 13 to import existing key

  3. next you’ll be prompted for keygrip, the one from step 3’s output

  4. you can leave the rest as defaults, so Q,0,y,y and finally save

  5. check if the key was correctly imported and if the fingerprint matches your originally generated vanity key: $ gpg --list-keys --keyid-format LONG

  6. repeat for every subkey you want to import

  7. export and reimport the whole keyring so that you have the subkeys instead of multiple primary keys:

$ gpg --export-secret-keys YOUR_ID_HERE > keyring.pgp
$ mv .gnupg gnupg-old
$ systemctl --user restart gpg-agent
$ gpg --import keyring.pgp
  1. another recommendation is to take an offline backup of the keyring and delete the primary key

This should result in a keyring with subkeys that have vanity fingerprints preserved. There are a few problems that can occur, like wrongly specifying the timestamp which would change the resulting fingerprint (though the key may still work?). The subkeys should be newer than the masterkey, therefore it may take trial and error since the vanity key generation is also helped through shuffling timestamps.

When importing my old RSA keys as subkeys, I also tried preserving their creation date by faking time, which backdated the signatures on them as well. Everything described here is basically a “hack” and definitely not a recommended/supported use case. What helped in this case was running the change-usage command in the gpg –edit-key shell on all of these subkeys and changing their capabilities to anything else and then changing them back.

My resulting public key can be found here: https://keyserver.plantroon.com/pks/lookup?op=get&search=plantroon%40plantroon.com

Here is the resulting keyring as shown by gpg:

plantroon@liberty:~$ gpg2 -K --keyid-format=LONG
/home/plantroon/.gnupg/pubring.kbx
----------------------------------
sec   ed25519/12248C0FFEEC0C0A 2022-12-06 [C]
      150605326D8A8300D6A4D94D12248C0FFEEC0C0A
uid                 [ultimate] Jakub Filo <plantroon@plantroon.com>
ssb   ed25519/7DA8C0FFEED0C0DE 2023-04-05 [S]
ssb   cv25519/2440D3B7C7DEC0DE 2022-12-26 [E]
ssb   ed25519/897AF56EC9ACCE55 2023-05-12 [A]
ssb   rsa4096/82EEE060B2048A55 2019-02-22 [SA]
ssb   rsa4096/22805B40C4BB6108 2019-02-22 [E]