clean up your GnuPG keyring

For reasons too annoying to explain, my GnuPG keyring was huge. It was taking a long time to find keys, and most of them weren’t ones I’d use. So I wrote this little script that strips out all of the keys that aren’t

  1. yours, or
  2. signatories to your key.

The script doesn’t actually delete any keys. It produces shell-compatible output that you can pipe or copy to a shell. Now my keyring file is less than 4% the size (or more precisely, 37‰) of the size it was before.

#!/bin/bash
# clean_keyring.sh - clean up all the excess keys

# my key should probably be the first secret key listed
mykey=$(gpg --list-secret-keys | grep '^sec' | cut -c 13-20 | head -1)
if
    [ -z $mykey ]
then
    # exit if no key string
    echo "Can't get user's key ID"
    exit 1
fi

# all of the people who have signed my key
mysigners=$(gpg --list-sigs $mykey | grep '^sig' | cut -c 14-21 | sort -u) 

# keep all of the signers, plus my key (if I haven't self-signed)
keepers=$(echo $mykey $mysigners | tr ' ' '\012' | sort -u)

# the keepers list in egrep syntax: ^(key|key|…)
keepers_egrep=$(echo $keepers | sed 's/^/^(/; s/$/)/; s/ /|/g;')

# show all the keepers as a comment so this script's output is shell-able
echo '# Keepers: ' $keepers

# everyone who isn't on the keepers list is deleted
deleters=$(gpg --list-keys | grep '^pub'|  cut -c 13-20 | egrep -v ${keepers_egrep})

# echo the command if there are any to delete
# command is interactive
if
    [ -z $deleters ]
then
    echo "# Nothing to delete!"
else
    echo 'gpg --delete-keys' $deleters
fi

Files:

3 comments

  1. Nice script – just what I needed just now.

    Unfortunately it has a few flaws for my use – shared here in case it is useful for others:

    the -z tests take a single argument, so variable needs to be quoted (it can expand to nothing or multiple arguments).

    gpg should use –with-colons option in scripts (breaks e.g. with gpg2 and non-US locales), and key can then be had piping through “cut -d: -f5”

    gpg should use –batch option in scripts. Particularly the last one, which (if you dare) could also use –yes option to be fully automated.

    There’s no benefit in grabbing only first key with secret key: gpg fails if told to remove a key that has a corresponding secret key. Better is to simply treat _all_ keys with secret key as “mine”.

  2. Thanks for the tips. It was definitely an ad hoc script that worked for me. As with everything on the web, use at your own risk.

  3. Great script but in my case I have an old secret key revoked that appears before than current secret key.
    But it been easy to solve adding a “grep -v expires” before “grep ^sec” to get only the valid secret key.

Leave a comment

Your email address will not be published. Required fields are marked *