ChrisKim
Do not go gentle into that good night.
颢天

使用 GPG 对你的 Git 提交进行签名验证

最近我在逛别人的 GitHub 仓库的时候,发现有些提交右侧有一个独特的绿色标识写着 verified,查了下资料才知道,这是使用 GPG 签名验证过的提交,因此会显示已验证的标志。这篇文章就分享如何使用 GPG 给 Git commit 签名。

GPG 的功能

GPG,全称 GNU Privacy Guard,顾名思义就是用来保护隐私数据的。其原理是非对称加密,分有公钥和私钥,公钥加密私钥才能解密,私钥加密公钥才能解密。通过这个原理,GPG 实现了四个功能:

  • [C] Certificating: 认证其他密钥、签名其他证书。
  • [S] Signing: 签名。
  • [A] Authenticating: 身份验证、鉴权。
  • [E] Encrypting: 加密。

我们给 Git commit 签名就用到了第二个功能,它可以验证这个 commit 是不是你本人提交的,是否被别人冒名顶替,如此保证了开源软件的安全性。

使用 GPG 给提交签名

检查 GPG 安装

如果你在阅读这篇文章,肯定是安装了而且会使用 Git 的。GPG 在 GitBash 中自带,因此我们理论上不需要额外安装。打开 GitBash,使用 gpg --version 命令即可查看当前 GPG 版本信息如下:

$ gpg --version
gpg (GnuPG) 2.2.29-unknown
libgcrypt 1.9.3-unknown
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /c/Users/<UserName>/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

生成 GPG 密钥

第一次使用 GPG,我们先要给自己生成一个 GPG 密钥。使用 gpg --full-generate-key 指令生成自定义密钥。

生成密钥有一些选项,首先是密钥类型和密钥长度,默认即可。然后是密钥有效期,没有特殊需求的话选择不失效会比较方便。

然后进入密钥信息的填写,首先是姓名,接下来邮箱比较重要,需要和你的代码托管平台例如 GitHub 的邮箱保持一致,否则将无法导入你的公钥。备注不是很重要,可以空着。

然后弹出 Pinentry 窗口,设置你的密钥的密码。以后使用密钥需要输入该密码。

gpg: revocation certificate stored as '/c/Users/<UserName>/.gnupg/openpgp-revocs.d/<ID>.rev'
public and secret key created and signed.

pub   rsa3072 2022-05-28 [SC]
      <ID>
uid                      <Name> <E-mail>
sub   rsa3072 2022-05-28 [E]

这样就成功生成了你的密钥。今后也可使用 gpg --list-keys 列出当前设备上的公钥。

使用 GPG 给提交签名

首先设置 Git 使用的密钥:(<ID> 就是生成密钥后显示的那一行字符)

git config --global user.signingkey <ID>

此时就已经可以使用 GPG 签名提交了,只需在每次提交时加上 -S 参数,如:

git commit -S -m "Commit Message"

如果默认每次提交都要使用 GPG 签名,可以设置:

git config --global commit.gpgsign true

设置后加不加 -S 都会使用 GPG 签名提交。

之后提交时,均会弹出 Pinentry 窗口,需要输入对应密钥的密码才可以提交代码。

GitHub 导入 GPG 公钥

我们需要将自己的公钥导入 GitHub,这样 GitHub 才能验证我们的提交是否是本人。

首先导出我们的公钥,使用 gpg --armor --export <ID> 导出 ASCII 编码后的公钥(要不然就是二进制数据了),将公钥内容完整复制下来。

在 Settings 中找到 SSH and GPG keys 页面,点击 New GPG Keys,粘贴公钥保存即可。

这样操作之后,我们的提交在 GitHub 上均会标有 verified 标识。

一些其他操作

导入并信任 GitHub 的公钥

由于有时候我们会直接在 GitHub 上提交,此时这个提交是使用 GitHub 的密钥签名的,在我们本地就会显示无法验证的签名,并且被标红了。使用 git log --show-signature 就可以发现这个现象如下:

commit b30d6a82b62e49665aa7d6964f528381c1ba72c4
gpg: Signature made 2022年05月16日 23:52:13
gpg:                using RSA key 4AEE18F83AFDEB23
gpg: Can't check signature: No public key
Author: Haotian Zou <49368462+ChrisKimZHT@users.noreply.github.com>
Date:   Mon May 16 23:52:13 2022 +0800

这样很碍眼,因此我们得导入并信任 GitHub 的公钥,这样我们本地的 Git 就能验证该提交。

首先是导入:curl https://github.com/web-flow.gpg | gpg --import

然后是信任:gpg --sign-key 4AEE18F83AFDEB23

输入自己密钥的密码,使用自己的密钥为它签名验证。这样提交变成蓝色的已验证的了:

commit b30d6a82b62e49665aa7d6964f528381c1ba72c4
gpg: Signature made 2022年05月16日 23:52:13
gpg:                using RSA key 4AEE18F83AFDEB23
gpg: Good signature from "GitHub (web-flow commit signing) <noreply@github.com>" [full]
Author: Haotian Zou <49368462+ChrisKimZHT@users.noreply.github.com>
Date:   Mon May 16 23:52:13 2022 +0800

导出自己的私钥

如果我们想在不同设备共有一个密钥,就需要导出自己的私钥,例如我想在本机的 wsl2 中使用相同的密钥。通常,这种操作不太安全,不建议进行导出。

gpg --output <Name>.pgp --armor --export-secret-key <ID>

导出时需要输入密码。导出后获得一个密钥文件,将其移动到对应设备,切记保管好私钥文件,重新导入后删除销毁。

导入并信任私钥

在对应设备运行指令:gpg --import <KeyFile> 即可导入公/私钥,私钥导入需要输入密码。

如果仅导入私钥,那么该密钥会在列表中显示为 [ unknown ],它本该为 [ ultimate ],我们需要信任该密钥。

运行指令:gpg --edit-key <E-mail>,然后再输入 trust,选择“绝对信任”选项,再输入 save 保存即可。整个过程如下:

gpg --edit-key user@useremail.com

gpg> trust

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

在 WSL2 中使用 GPG

如果我们按以上步骤配置好了 WSL2 的 GPG 密钥和 Git,想要提交时结果发现:

error: gpg failed to sign the data
fatal: failed to write commit object

原因是 WSL2 没法弹出 Pinentry 窗口,也就是我们没法输入密钥的密码,因此将无法提交。解决方法是让 WSL2 使用 Windows 主机上的 pinentry-basic.exe 来接受密码。

似乎 Git 自带的 GPG 没法实现这个操作,因此我们需要额外安装一个 GPG4Win,安装后 pinentry-basic.exe 的目录不出意外应该为:”C:\Program Files (x86)\GnuPG\bin\pinentry-basic.exe”

然后我们编写(不存在则创建)WSL2 中的文件 ~/.gnupg/gpg-agent.conf,在里面添加

pinentry-program "/mnt/c/Program Files (x86)/GnuPG/bin/pinentry-basic.exe"

这样在 WSL2 中提交,就会在 Windows 主机上弹出窗口接受密钥的密码。至此就可以在 WSL2 中顺利提交了。

本文链接:https://www.zouht.com/2891.html
本文使用:CC BY-NC-SA 4.0 许可
# # #
首页      教程      使用 GPG 对你的 Git 提交进行签名验证

发表回复

textsms
account_circle
email

  • Github Desktop 的提交自带签名吗?

    2 年前 回复
  • 这个不弹出 Pinentry 窗口在 Termux 上要用一行 export GPG_TTY=$(tty) 来解决。这样每次提交都要输一次密码,手机屏幕这么小,手残党果断放弃…… [笑哭]

    2 年前 回复
    • ChrisKim

      @CasecoRI: 哈哈哈,不如把缓存时间开得很长,这样除非重启设备,第一次输密码后之后就不用输了。 [原神_欸嘿]

      2 年前 回复
  • 补充一下,如果要删除密钥,有三个选项:
    –delete-keys、–delete-secret-keys 和 –delete-secret-and-public-key。
    –delete-keys 表示从公钥钥匙圈上删除密钥,也就是一同删除公钥和对应的私钥。在分批模式(batch mode)下,密钥必须使用指纹表示,或者使用 –yes 选项。
    –delete-secret-keys 表示从私钥钥匙圈上删除密钥。
    –delete-secret-and-public-key 和 –delete-keys 一样,但是如果私钥存在的话,会先移除私钥。在分批模式下,密钥必须使用指纹表示。

    2 年前 回复

颢天

使用 GPG 对你的 Git 提交进行签名验证
最近我在逛别人的 GitHub 仓库的时候,发现有些提交右侧有一个独特的绿色标识写着 verified,查了下资料才知道,这是使用 GPG 签名验证过的提交,因此会显示已验证的标志。这篇文章就分享…
扫描二维码继续阅读
2022-05-29