GPG + Git basics: How to generate keys, sign commits, and export keys to another machine
Dec 26, 2022
8 min read
In this article I will treat some interesting topics related to GPG keys and Git. I will explain what are GPG keys and what are they used for, how to generate them, how to use them to sign commits (and also how to add them to GitHub), and how to export them to another machine with ultimate trust.
What are GPG keys and what are they used for?
PGP ("Pretty Good Privacy") is an encryption program that provides cryptographic privacy and authentication for data communication. PGP is used for signing, encrypting, and decrypting texts, e-mails, files, directories, etc. It can be used to sign git commits too, which allows you and anyone else to verify the true authorship of a commit, in a cryptographic safe way.
This is a very useful feature to ensure that the commit is really from the author, and not from a malicious person trying to impersonate the author (which it is easy to achieve with Git, as all you have to do is to change the author name and email in the commit to "impersonate" someone).
If you ever wonder what are the "Verified" green check that appears near some commits in GitHub, those are commits that are signed with a GPG key that belongs to the author of the GitHub account and identifies the email used in the commit. More on that later.
GPG uses asymmetric cryptography to work. This means that there are two keys: a public key and a private key. The public key is used to encrypt data and verify signatures, and the private key is used to decrypt and sign data. The public key can be shared with anyone, but the private key must be kept secret.
Generating GPG keys
To generate a GPG key, you can use the
gpg command. You can found it in most Linux distros as a package with the
gnugp name, and also in MacOS with
brew. Once installed, we can continue with the following:
After executing this command, you will come through a guided process where you will be asked to select the type of key you want to generate. I recommend you to choose the default option, which is RSA and RSA, and also to choose a key size of 4096 bits, like so:
gpg (GnuPG) 2.2.19; Copyright (C) 2019 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Please select what kind of key you want: (1) RSA and RSA (default) (2) DSA and Elgamal (3) DSA (sign only) (4) RSA (sign only) (14) Existing key from card Your selection? 1 RSA keys may be between 1024 and 4096 bits long. What keysize do you want? (3072) 4096 Requested keysize is 4096 bits Please specify how long the key should be valid. 0 = key does not expire <n> = key expires in n days <n>w = key expires in n weeks <n>m = key expires in n months <n>y = key expires in n years Key is valid for? (0) 0 Key does not expire at all Is this correct? (y/N) y GnuPG needs to construct a user ID to identify your key. Real name: John Doe Email address: firstname.lastname@example.org Comment: You selected this USER-ID: "John Doe <email@example.com>" Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?
Ensure that you use a real email address, as this will be used to identify the key. You can also add a comment if you want. You can add a passphrase to the key if you want, but it is not mandatory. If you add a passphrase, you will have to enter it every time you use the key (similar to passphrase-protected SSH keys), which adds an extra layer of security.
Adding the new generated keys to Git to sign commits
Once you have generate the key, you can add it to Git to start signing commits. First, we need to know the key ID. To do so, we can use the following command:
gpg --list-secret-keys --keyid-format=long
/home/aalonso/.gnupg/pubring.kbx ------------------------------------ sec rsa4096/85D3AAC2A8C4989E 2022-12-26 [SC] 72DA3C7163C7D8FE854DC67D85D3AAC2A8C4989E uid [ultimate] John Doe <firstname.lastname@example.org> ssb rsa4096/8FD5D3E520A1B19C 2022-12-26 [E]
You can see an ID after
sec rsa4096/<THIS_IS_THE_ID>. In this case:
Now open your existing
.gitconfig file (or create it if it doesn't exist under
$HOME/.gitconfig) and add the following lines:
[user] name = John Doe email = email@example.com signingkey = 85D3AAC2A8C4989E
Now, you can start signing commits. To do so, you can use the
-S flag when you commit:
git commit -S -m "This is a signed commit"
If you want to sign all commits by default, you can add the following line to your
.gitconfig file under the previous added
[commit] gpgsign = true
Now, you can make your commits as always and the will be automatically signed.
git commit -m "This commit is signed by default"
Adding the new generate keys to GitHub for the "Verified" green check
First, we need to get the public key, which GitHub used to verify the commit signature. To do so, we can use the following command given the ID we got before:
gpg --armor --export 85D3AAC2A8C4989E
-----BEGIN PGP PUBLIC KEY BLOCK----- blah blah blah -----END PGP PUBLIC KEY BLOCK-----
Copy the entire GPG key, beginning with
-----BEGIN PGP PUBLIC KEY BLOCK----- and ending with
-----END PGP PUBLIC KEY BLOCK-----, and follow the official steps to add it to your GitHub account. Similar step-by-step instructions can be found for other platforms such as GitLab or Bitbucket in their related official docs.
Exporting GPG keys to another machine
If you want to export your GPG keys to another machine, so let's say you have a laptop and a desktop, you can do so by following the next steps.
First, in the machine where you generate the GPG keys, you need to export the secret. To do so, you can use the following command:
gpg --export-secret-key -a firstname.lastname@example.org > test_key.priv
If your private key is protected by a passphrase, it will be asked. Now, copy the exported key to the machine where you want to import it. Be sure to do this via a safe channel, so you don't compromise your private key, specially if it is not protected by a passphrase. You can use
scp for that.
scp test_key.priv user@host:/path/to/destination
Once the exported private key file is in the destination machine, you can import it with the following command:
gpg --import test_key.priv
Congrats! You have successfully exported your GPG keys to another machine. However, if you does
gpg --list-secret-keys --keyid-format=long, you will see the key is not trusted by default, as it is from an "unknown" source.
/home/aalonso/.gnupg/pubring.kbx ------------------------------------ sec rsa4096/85D3AAC2A8C4989E 2022-12-26 [SC] 72DA3C7163C7D8FE854DC67D85D3AAC2A8C4989E uid [unknown] John Doe <email@example.com> ssb rsa4096/8FD5D3E520A1B19C 2022-12-26 [E]
This won't affect your ability to use it to sign commits, but it is a good thing to solve this in case you need it for another tasks. To do so, you can use the following command:
gpg --edit-key -a firstname.lastname@example.org
Now, in the gpg prompt, use the
trust command to ultimately trust the key, and save the changes with the
gpg (GnuPG) 2.2.19; Copyright (C) 2019 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Secret key is available. sec rsa4096/85D3AAC2A8C4989E created: 2022-12-26 expires: never usage: SC trust: undefined validity: unknown ssb rsa4096/8FD5D3E520A1B19C created: 2022-12-26 expires: never usage: E [ unknown] (1). John Doe <email@example.com> gpg> trust sec rsa4096/85D3AAC2A8C4989E created: 2022-12-26 expires: never usage: SC trust: undefined validity: unknown ssb rsa4096/8FD5D3E520A1B19C created: 2022-12-26 expires: never usage: E [ unknown] (1). John Doe <firstname.lastname@example.org> Please decide how far you trust this user to correctly verify other users' keys (by looking at passports, checking fingerprints from different sources, etc.) 1 = I don't know or won't say 2 = I do NOT trust 3 = I trust marginally 4 = I trust fully 5 = I trust ultimately m = back to the main menu Your decision? 5 Do you really want to set this key to ultimate trust? (y/N) y sec rsa4096/85D3AAC2A8C4989E created: 2022-12-26 expires: never usage: SC trust: ultimate validity: unknown ssb rsa4096/8FD5D3E520A1B19C created: 2022-12-26 expires: never usage: E [ unknown] (1). John Doe <email@example.com> Please note that the shown key validity is not necessarily correct unless you restart the program. gpg> save
That's it! Now, the key should show
ultimate trust as in the original machine where it was generated. Don't forget to update the
.gitconfig in the destination machine to use the new imported GPG key to sign commits!