GitHub recently added support for signed commits. The instructions for setting it up can be found on their website and I do not intend to rehash them here. I followed those instructions and they work splendidly. However, when I set mine up, I had used the version of GPG that came with my Git installation. A side effect I noticed was that if I were rebasing some code and wanted to make sure the rebased commits were still signed (by running git rebase
with the -S
option), I would have to enter my passphrase for the GPG key for every commit (which gets a little tedious after the first five or so).
Now, there are a couple of ways to fix this. One is easy; just don't use a passphrase protected key. Of course, that would make it a lot easier for someone to sign commits as me if they got my key file, so I decided that probably was not the best option. Instead, I did a little searching and found that GPG2 supports passphrase protected keys a little better than the version of GPG I had installed as part of my original git installation.
Using the GPG4Win website, I installed the Vanilla version1. I then had to export the key I had already setup with GitHub from my old GPG and import it into the new. Using gpg --list-keys
, I obtained the 8 character ID for my key (the bit that reads BAADF00D
in this example output):
gpg: WARNING: using insecure memory! gpg: please see http://www.gnupg.org/documentation/faqs.html for more information /c/Users/Jeff/.gnupg/pubring.gpg -------------------------------- pub 4096R/BAADF00D 2016-04-07 uid Jeff Yates <jeff.yates@example.com> sub 4096R/DEADBEEF 2016-04-07
Which I then used to export my keys from a Git prompt:
gpg -a --export-secret-keys BAADF00D > privatekey.txt gpg -a --export BAADF00D > publickey.txt
This gave me two files (privatekey.txt
and publickey.txt
) containing text representations of the private and public keys.
Using a shell in the GPG2 pub folder ("C:\Program Files (x86)\GNU\GnuPG\pub"
), I then verified them (always a good practice, especially if you got the key from someone else) before importing them2:
> gpg privatekey.txt
And rather than give me details of the key, it showed me this error:
gpg: no valid OpenPGP data found. gpg: processing message failed: Unknown system error
What was going on? I tried verifying it with the old GPG and it gave me a different but similar error:
gpg: WARNING: using insecure memory! gpg: please see http://www.gnupg.org/documentation/faqs.html for more information gpg: no valid OpenPGP data found. gpg: processing message failed: eof
I tried the public key export and it too gave these errors. It did not make a whole heap of sense. Trying to get to the bottom of it, I opened the key files in Visual Studio Code. Everything looked fine until I saw this at the bottom of the screen.
It turns out that Powershell writes redirected output as UTF-16
and I had not bothered to check. Thinking this might be the problem, I resaved each file as UTF-8
and tried verifying privatekey.txt
again:
sec 4096R/BAADF00D 2016-04-07 uid Jeff Yates <jeff.yates@example.com> ssb 4096R/DEADBEEF 2016-04-07
Success! Repeating this for the publickey.txt
file gave the exact same information. With the keys verified, I was ready to import them into GPG2:
> gpg --import publickey.txt
gpg: WARNING: using insecure memory! gpg: please see http://www.gnupg.org/documentation/faqs.html for more information gpg: key BAADF00D: public key "Jeff Yates <jeff.yates@example.com>" imported gpg: Total number processed: 1 gpg: imported: 1 (RSA: 1)
> gpg --import privatekey.txt
gpg: WARNING: using insecure memory! gpg: please see http://www.gnupg.org/documentation/faqs.html for more information gpg: key BAADF00D: secret key imported gpg: key BAADF00D: "Jeff Yates <jeff.yates@example.com>" not changed gpg: Total number processed: 1 gpg: unchanged: 1 gpg: secret keys read: 1 gpg: secret keys imported: 1
With the keys imported, I ran gpg --list-keys
to verify they were there and then made sure to delete the text files.
Finally, to make sure that Git used the new GPG2 instead of the version of GPG that it came with, I edited my Git configuration:
> git config --global gpg.program "C:\Program Files (x86)\GNU\GnuPG\pub\gpg.exe"
Now, when I sign commits and rebases, instead of needing to enter my passphrase for each commit, I am prompted for the passphrase once. Lovely.