Antony Jepson
🤔 About
✍️ Contact
21 Sep 2020

Rotating expired Nitrokey subkeys used for password store
5 July 2020

I’m currently managing my saved passwords with a mixture of pass and Nitrokey. One of my sub-keys expired so I couldn’t update my passwords. Here’s how I generated new keys (rotated them) with a new expiration date.

You’ll need access to your master key. Most tutorials online will make you generate the key locally, nerf it, and upload it into the Nitrokey. In this case, you’ll need find the original primary signing key before moving forward.

Once you have it in hand, extract the contents to a temporary directory and let’s begin. Don’t forget to set the directory permissions appropriately (chmod 700 ./). We’ll be using gpgh to refer to this new directory we’re using for gpg.

$ alias gpgh="gpg --homedir $(pwd)"

$ gpgh --import user@domain.tld.gpg-private-keys
< enter password >

Trust the keys.
$ gpgh --edit-key user@domain.tld
gpg> trust

< select 5 for maximum trust >
< select y to confim >
< exit to confirm >

Modify expiry date of primary key.
$ gpgh --expert --edit-key user@domain.tld
gpg> expire

< select and confirm a new timeframe >

Generate new subkeys.
gpg> list
sec brainpoolP384r1/DEADBEEFDEADBEE1
created: 2019-XX-XX expires: 2021-XX-XX usage: SC
trust: ultimate validity: ultimate
ssb brainpoolP384r1/DEADBEEFDEADBEEA
created: 2019-XX-XX expired: 2020-XX-XX usage: E
ssb brainpoolP384r1/DEADBEEFDEADBEEB
created: 2019-XX-XX expired: 2020-XX-XX usage: S
ssb brainpoolP384r1/DEADBEEFDEADBEEC
created: 2019-XX-XX expired: 2020-XX-XX usage: A
[ultimate] (1). User Name

Generate new subkeys
gpg> addkey
< select 12 to replace subkey BEEA >
< select 7 for brainpool p-384 >
< select 6m for six months >
< select y then y to confirm >
gpg> addkey
< select 10 to replace subkey BEEB >
< select 7 for brainpool p-384 >
< select 6m for six months >
< select y then y to confirm >
gpg> addkey
< select 11 to replace subkey BEEC >
< select A to toggle authenticate capability >
< select S to toggle authenticate capability >
< select Q to finish >
< select 7 for brainpool p-384 >
< select 6m for six months >
< select y then y to confirm >

Remove the expired subkeys
gpg> key 1
gpg> key 2
gpg> key 3
gpg> delkey

Export private and public keys to prepare for backup.
$ gpgh --armor --export-secret-keys user@domain.tld > user@domain.tld-private-keys-2020-07-05
$ gpgh --armor --export user@domain.tld > user@domain.tld-public-keys-2020-07-05

Generate a new revocation certificate
$ gpgh --gen-revoke user@domain.tld > user@domain.tld.gpg-revocation-certificate-2020-07-05

Encrypt the private keys, public keys, and revocation certificate in a symmetrically encrypted tarball and send to offsite.
$ tar cf ./user@domain.tld-keys-2020-07-05.tar user@domain.tld-*-2020-07-05
$ gpgh --symmetric --cipher-algo aes256 user@domain.tld-keys-2020-07-05.tar
$ rm user@domain.tld-keys-2020-07-05.tar
$ sendoffsite user@domain.tld-keys-2020-07-05.tar.gpg
$ sendoffsite user@domain.tld-public-keys-2020-07-05

Import new subkeys into Nitrokey, replacing existing subkeys
< plug in Nitrokey>

$ gpgh --expert --edit-key user@domain.tld
gpg> key 1
gpg> keytocard

< select 2 for encryption key >
< enter master key password >
< enter admin pin for nitrokey >
gpg> key 1
gpg> key 2
gpg> keytocard

< select 1 for signature key >
< enter master key password >
gpg> key 2
gpg> key 3
gpg> keytocard

< select 3 for authentication key >
< enter master key password >
gpg> save

(Note down the encryption key from the “list” output so you can re-initialise pass later.)

Kill the running GPG agents that might interfere with password caching.
$ gpgconf --kill gpg-agent
$ GNUPGHOME=$(pwd) gpgconf --kill gpg-agent

Confirm those sneaky buggers are gone.
$ ps aux | grep gpg

Migrate your pass store to the new set of keys. You’ll need to do this with both the old and new set of keys accessible so we’ll run this from our temporary directory with the expired sub-keys.

First cache the password of the private key.
$ echo "test message string" | gpgh --encrypt --armor --recipient user@domaind.tld -o encrypted.txt
$ gpgh --decrypt --armor encrypted.txt

Confirm you can decrypt an existing pass key.
$ gpgh --decrypt ~/.password-store/some/key/user@domain.tld.gpg

Backup pass directory
$ cp -R ~/.password-store ~/.password-store_bak

Next migrate the passwords, using the encrypted subkey we listed above.

Create and delete a fake password to confirm it’s working.
$ PASSWORD_STORE_GPG_OPTS="--homedir $(pwd)" pass generate fake/password
$ PASSWORD_STORE_GPG_OPTS="--homedir $(pwd)" pass edit fake/password
$ PASSWORD_STORE_GPG_OPTS="--homedir $(pwd)" pass rm fake/password

Finally, update your local GPG configuration by importing the new public keys. Notice we’re using the normal gpg. You should see 3 new subkeys imported.
$ gpg --import user@domain.tld-public-keys-2020-07-05

Now you can remove the temporary directory you made after confirming you’ve backed up the encrypted backup and also published the public keys somewhere accessible.
$ rm -r $(pwd)
$ cd

More articles I’ve written on this topic:
* Using GPG to master your identity (Part 1)
* Configuring and integrating Nitrokey into your workflow

Customising Email Signatures with Fortune
1 August 2008

When I look at someone’s email signature and see a thought-provoking quote like “Violence is the last refuge of the incompetent” (Salvor Hardin), I add it to my mental list of quotes, which, of course, is soon forgotten. Now, with a bit of pipe magic, I can use Mutt and fortune to make my signatures a bit more creative.

Preparing the database

1. Create a .fortune file in your home directory and insert your quotes.  Separate each quote/phrase with a % (percentage sign).

~ %   touch ~/fortune
~ %   vim ~/fortune
  1 De duobus malis minus est semper eligendum.
  2   -- Thomas a Kempis
  3 %
  4 Sic transit gloria mundi.
  5   -- Thomas a Kempis
  6 %

2. Randomise access to the strings with strfile.

~ %   strfile -r ~/fortune ~/fortune.dat
"/home/antony/fortune.dat" created
There were 2 strings
Longest string: 65 bytes
Shortest string: 47 bytes

To save yourself embarrassment in the future, keep your quotes short and SFW.

Integrating the database with Mutt

3. Create a simple script to use with Mutt.

~ %   touch bin/signature.sh
~ %   vim bin/signature.sh
  1 #!/bin/bash
  3 cat ~/.signature
  4 fortune ~/fortune
~ %   chmod +x bin/signature.sh

4. Finally, set the script as Mutt’s default signature.

~ %   vim ~/.mutt/muttrc
17 set signature="~/bin/signature.sh |"

Now you can enjoy creative, original signatures in your emails.

After a bit of thought, I came up with a heavily customised signature script that will: print the contents of ~/.signature, append a justified fortune quote from my database and right justify the attributed author.  Of course, it needs some work because the last line is right justified regardless of if there is an attributed author or not.

1 #!/bin/bash
3 fortune ~/fortune | sed -e 's/^/++ /' -e 's/$/ ++/' > /tmp/signature.1
4 sed -n '$!p' /tmp/signature.1 | par -58s3p3 > /tmp/signature.2
5 tail -n1 /tmp/signature.1 | sed -e :a -e 's/^.\{1,56\}$/ &/;ta' -e 's/++/\ \ /' -e 's/^./++/' >> /tmp/signature.2
6 cat ~/.signature
7 cat /tmp/signature.2

outputting something similar to:

Antony Jepson / <aaaaaaaa@gmail.com> / GPG Key: 0x00000000
++ Sapere aude! (Dare to be wise!)                      ++
++                          -- Quintus Horatius Flaccus ++
Configuring the default prompt (PS1)
20 July 2008

I use the terminal every day and I have spent a lot of time customising its configuration, particularly the default prompt, to my liking.

Today, I will show you how to customise your default prompt, or PS1.  Before I show you my spartan configuration, let me explain.  I am a minimalist, so I do not see the point of having a long PS1 that shows a multitude of system information when the core *nix utils (/bin) can tell you that anyway.

Note: My terminal is rxvt-unicode, my shell is zsh, and I often run all my cli apps within GNU screen.

PS1="$(print '%{\e[1;31m%}%1%{\e[0m%} %{\e[1;32m%}%B%#%b%{\e[0m%} %(?..(%?%)) %_ \ek\e\\')"

Produces: ~ %

Explanation:  The entire PS1 expression is placed within a print command so my shell outputs a “null title-escape-sequence (<esc>k<esc>\) as a part of the prompt.”  GNU screen will then use the title-escape-sequence when naming the window (normally changed with C-a A).


– light red


– trailing component of $PWD


– resets the color


– light green


– start boldface mode


– prints a # if I am a superuser (root) or a % if I am not.


– end boldface mode


– resets the color


– takes advantage of zsh’s ternary expressions, which picks different strings depending on a test.  In this case, a message is displayed only if the exit code is not zero.


: status of the parser (i.e. if, for, then, while)


– the title-escape-sequence for GNU screen

Other common variables you can use include:


– history entry number


– current hostname (up to any dot)


– shows username


– the date in yy-mm-dd format

See “zsh: Prompt Expansion” for the definitive list of zsh prompt sequences.

A list of “colour equivalences:”

Black       0;30     Dark Gray     1;30
Blue        0;34     Light Blue    1;34
Green       0;32     Light Green   1;32
Cyan        0;36     Light Cyan    1;36
Red         0;31     Light Red     1;31
Purple      0;35     Light Purple  1;35
Brown       0;33     Yellow        1;33
Light Gray  0;37     White         1;37

Using a handy script I got from the bash manual, here is a picture of my current color scheme (zenburn):

My Desktop – The Terminal
6 July 2008

AJ\'s Workspace (2008-06-25)This will be the final post covering my desktop.
If you look in the bottom left corner of the screenshot, you will see my terminal, rxvt-unicode.

For the most part, I’m a cli person.  I prefer the terminal because of it’s speed.

In the terminal, you can see me running irssi (an irc client) within screen, a detachable terminal multiplex.  Basically, screen allows me to continue using the terminal’s applications even in the event of an X server crash.tirssit

A terminal is basically a portal into the underlying filesystem of my Linux installation.  Much like a MS-DOS prompt, it allows me to navigate this hidden infrastructure with uncanny ease.

Some of my frequently used terminal programs include:

gnu mc (midnight commander) – a file browser

irssi – an irc client (you can find me on freenode)

vim – a text editor (although capable of much, much more)

abcde (A Better CD Encoder) – a cd ripper (makes ripping easy)

nethack – a great rpg

ncmpc – a cli client for mpd (the music player daemon)

mutt – my favourite mail user agent

Built with Wordpress and Vim
© 2008 to 2020 Antony Jepson