Подпись (в частности — подпись кода) представляет собой процесс использования шифрования для добавления цифровой подписи к данным. Получатель данных может проверить достоверность подписи и убедиться, что послание пришло именно от указанного отправителя.

GNU Privacy Guard (GnuPG или GPG) позволяет создавать асимметричные пары ключей, которые можно использовать для шифрования и подписи данных. Каждая пара состоит из открытого и закрытого ключа.

Открытым ключом можно поделиться с кем угодно. Вы можете загрузить его в свои учетные записи GitHub и GitLab или разместить в Интернете, чтобы любой мог получить к нему доступ. Закрытый ключ, он же секретный, известен только владельцу. При помощи закрытого ключа происходит создание подписи, а при помощи открытого ключа кто угодно может проверить электронную подпись.

Подготовка

Чтобы работать с ключами нам надо установить gnupg и pinentry-mac.

brew install gnupg pinentry-mac

И настроить конфиг для GPG агента

$ cat > .gnupg/gpg-agent.conf <<EOF
use-standard-socket
enable-ssh-support
default-cache-ttl 14400
max-cache-ttl 86400
pinentry-program /opt/homebrew/bin/pinentry-mac
EOF

Чтобы новые настройки применились надо перезапустить агента, а точнее убить старого, а новый запустится автоматом.

gpgconf --kill gpg-agent

Генерация ключей

Переходим к ключам. Для начала нам надо сгенерировать пару.

$ gpg --full-generate-key
gpg (GnuPG) 2.3.4; Copyright (C) 2021 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
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
   (9) ECC (sign and encrypt) *default*
  (10) ECC (sign only)
  (14) Existing key from card
Your selection? 9
Please select which elliptic curve you want:
   (1) Curve 25519 *default*
   (4) NIST P-384
   (6) Brainpool P-256
Your selection? 1
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: Michael Bruskov
Email address: mixanemca@yandex.ru
Comment: Example GPG key pair
You selected this USER-ID:
    "Michael Bruskov (Example GPG key pair) <mixanemca@yandex.ru>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: revocation certificate stored as '/Users/mbr/.gnupg/openpgp-revocs.d/2800BA0967A8161D7D177DEEB5AE319DE4956950.rev'
public and secret key created and signed.

pub   ed25519 2022-04-21 [SC]
      2800BA0967A8161D7D177DEEB5AE319DE4956950
uid                      Michael Bruskov (Example GPG key pair) <mixanemca@yandex.ru>
sub   cv25519 2022-04-21 [E]

После подтверждения запустится pinentry-mac и попросит ввести парольную фразу. pinentry-mac Можно установить любое значение или оставить поле пустым. Конечно, в идеале нужно придумать хороший, сильный пароль. Воспользуйтесь для этого своим менеджером паролей.

Список имеющихся GPG-ключей можно получить с помощью команды:

$ gpg --list-keys
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2u
/Users/mbr/.gnupg/pubring.kbx
-----------------------------
pub   ed25519 2022-04-21 [SC]
      2800BA0967A8161D7D177DEEB5AE319DE4956950
uid           [ultimate] Michael Bruskov (Example GPG key pair) <mixanemca@yandex.ru>
sub   cv25519 2022-04-21 [E]

Включаем подпись коммитов и тегов

Отлично, ключи у нас есть, настрало время добавить из в Git. Я подписываю все теги и коммиты, так что добавляю настройки в глобальный .gitconfig, но можно включать и на уровне отдельного репозитория.

git config --global commit.gpgsign true
git config --global tag.gpgSign true
git config --global log.showSignature true

Осталось только указать, каким ключом подписывать.

git config --global user.signingkey 2800BA0967A8161D7D177DEEB5AE319DE4956950

Экспорт публичного ключа

Для того, чтобы загрузить наш открытый ключ на GitHub или GitLab его нужно экспортировать

$ gpg --export --armor 2800BA0967A8161D7D177DEEB5AE319DE4956950
-----BEGIN PGP PUBLIC KEY BLOCK-----

mDMEYmHOHBYJKwYBBAHaRw8BAQdARKqQPRA3ZtJWDM1hkRsOhFBfpogvLRDLw1DR
9KGFevi0PE1pY2hhZWwgQnJ1c2tvdiAoRXhhbXBsZSBHUEcga2V5IHBhaXIpIDxt
aXhhbmVtY2FAeWFuZGV4LnJ1PoiUBBMWCgA8FiEEKAC6CWeoFh19F33uta4xneSV
aVAFAmJhzhwCGwMFCwkIBwIDIgIBBhUKCQgLAgQWAgMBAh4HAheAAAoJELWuMZ3k
lWlQVmYBAI1xT4W2YNh1WaGEFxsi9bua/+tuWP55p9BVH3zyRSXQAPwLrAWDdA8E
c+QhEm6wNu02bl3SN2G4CRhz7zzwSVogCLg4BGJhzhwSCisGAQQBl1UBBQEBB0AS
T4n0mcCK8zH0VwMXo2klodF/5oNjTUtkPAczaR38XgMBCAeIdwQYFgoAIBYhBCgA
uglnqBYdfRd97rWuMZ3klWlQBQJiYc4cAhsMAAoJELWuMZ3klWlQp4gA93nQBnbk
oBsQvuVgd5FzM0EO2h6doDbdfcm3EWfo9T4A/iU5qTyDOiGlZYoLDeYX4GGuDe/E
KcWd5U3mx0CTTkwL
=/Nc3
-----END PGP PUBLIC KEY BLOCK-----

Как сделать резервную копию

Закрытый ключ можно экспортировать почти так же, как мы экспортировали открытый

gpg --export-secret-keys --armor 2800BA0967A8161D7D177DEEB5AE319DE4956950 > gpg-key.asc

Если к ключу задана парольная фраза, то опять запустится pinentry-mac и попросит ее ввести.