Signing Git commits with GPG keys that use modern encryption
Tags: git, encryption, gpg, ellipticcurve
Published: 2021-01-02 23:39:55

*My posts are usually notes and reference materials for myself, which I publish here with the hope that others might find them useful.*


Git can be easily configured so that commits are cryptographically signed. [The Github documentation is fairly straightforward](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/telling-git-about-your-signing-key), but I find the defaults unpalatable, so I will tweak them a bit.

In particular, I prefer to use the strongest available modern encryption, specifically [EdDSA using SHA-512 and the 25519 curve, aka Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519).

Also, I like to create a signing-only subkey that is exclusively used for signing.

That requires some extra steps.

---

# Creating a Ed25519 master key

First, we make sure that GPG supports EdDSA public key cryptography:

```
$ gpg --version
...
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
```

If our version of GnuPG was built without support for EdDSA, we're out of luck.

Next, generating an Ed25519 master key is still considered an 'expert' option, so we invoke `gpg` with `--expert`, and for the first prompt, select option `(9) ECC and ECC` (**E**lliptic **C**urve **C**ryptography) for the type of key:

```
$ gpg --full-generate-key --expert
...
Please select what kind of key you want:
...
   (9) ECC and ECC
```

Choose option `(1) Curve 25519` for the next prompt:

```
Please select which elliptic curve you want:
   (1) Curve 25519
```

The rest of the prompts to generate the master key are straightforward.

Once it's finished we can confirm the new master key uses Ed25519 with `gpg --list-keys`.

```
$ gpg --list-keys --keyid-format short
...
---------------------------
pub   ed25519/4AC7128F 2021-01-02 [SC]
      [redacted]
uid         [ultimate] Benjamin Black <benjamin.black@example.com>
sub   cv25519/885EBFBA 2021-01-02 [E]
```

---

#  Creating a signing-only subkey

Observe that GPG creates the master key for signing (S) and for certificate creation (C) (`[SC]`), and automatically creates a subkey for encryption (`[E]`).

So we *can* use the master key for signing, and that is what both the Github and the [official Git documentation](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) suggest, but that is not best practice.

Instead, we should create a signing subkey explicitly for signing Git commits. We'll use the GPG CLI create it.

Begin by editing the master key, again passing `--expert`:

```
$ gpg --expert --edit-key 4AC7128F
...
sec  ed25519/B1ED9EFC4AC7128F
     created: 2021-01-02  expires: never       usage: SC  
     trust: ultimate      validity: ultimate
ssb  cv25519/78317B8E885EBFBA
     created: 2021-01-02  expires: never       usage: E   
[ultimate] (1). Benjamin Black <benjamin.black@example.com>

gpg>
```

Then use the GPG CLI command `addkey` and select option `(10) ECC (sign only)` for the first prompt, and option `(1) Curve 25519` for the second prompt.

```
gpg> addkey
Please select what kind of key you want:
...
  (10) ECC (sign only)
...
Your selection? 10
Please select which elliptic curve you want:
   (1) Curve 25519
...
Your selection? 1
```

Complete the rest of the steps, and then use the `save` command at the CLI prompt to save and exit.

```
gpg> save
$
```

Now if we list keys, we'll see the newly created signing key.

```
$ gpg --list-keys --keyid-format short
...
sub   ed25519/599D272D 2021-01-02 [S]
```

Finally, just tell Git to sign everything with this signing key (step 4 in the Github documentation).

```
$ git config --global user.signingkey 599D272D
```

And now our Git commits will be signed with a signing-only GPG subkey that uses Ed25519 encryption.