- 所有文章/
Canokey 签名和认证应用指南
本文目录
PGP、OpenPGP 和 GPG #
先简单了解一下 PGP、OpenPGP 以及 GPG 的区别
PGP #
PGP (Pretty Good Privacy) 是一套用于信息加密、验证的应用程序,主要开发者是 小菲利普·R·齐默尔曼,PGP 本身是商业应用程序,PGP Inc. 公司拥有 1991 年发布的原始 PGP 加密软件的版权,后来 PGP 的所有权在 1997~2010 年经历多次更迭,直到最终被 Symantec 公司收购发展至今。
OpenPGP #
OpenPGP 是一种 PGP 加密标准,1997 年,小菲利普·R·齐默尔曼 与 PGP.Inc 公司同意 IEFT 制定一项公开的互联网标准即 OpenPGP,术语「OpenPGP」也可以描述任何支持 OpenPGP 系统的应用程序。
GPG #
GnuPG (GNU Privacy Guard ,一般称作 GPG) 是一个密码学软件,由 Werner Koch 于 1999 年发布,GnuPG 是遵循 IEFT 制定的 OpenPGP 标准、并且与 PGP 兼容的自由软件,它确保了 PGP 与 Symantec PGP 工具及 OpenPGP 之间可以进行标准互操作。
安装 GPG 软件 #
绝大部分 Linux 发行版都已经默认安装了 GPG,在 Windows 下,本文并不是直接安装 Gpg4Win,在 Windows 下我们推荐使用 Scoop 仅安装 GPG 程序,如果你使用 Windows 且不知道 Scoop 是什么,可阅读 使用 Scoop 管理 Windows 下的软件和开发环境,
# 更新 Scoop 与 Scoop 软件库
scoop update
# 安装 GPG
scoop install gnupg
查看您的计算机上安装的 GPG 版本信息:
gpg --version
gpg (GnuPG) 2.3.4 # 这是 GPG 软件版本
libgcrypt 1.9.4
Copyright (C) 2021 g10 Code GmbH
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:\Scoop\apps\gnupg\current\home # 这是 GPG 工作的目录
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
CAMELLIA128, CAMELLIA192, CAMELLIA256
AEAD: EAX, OCB
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2
生成 PGP 密钥 #
生成密钥对 #
PGP 密钥的功能有:
- [C]
Certification key
用于认证(一般只给主密钥) - [S]
Signature key
用于签名(如:GitHub 签名提交) - [E]
Encryption key
用于加密 - [A]
Authentication key
用于身份认证(如:SSH 登录服务器、SSH 访问 GitHub 仓库)
在 Canokey 或者 Yubikey 这些智能卡内的 OpenPGP 应用拥有独立的 Signature key
、Encryption key
以及 Authentication key
卡槽,我们的主密钥 [C] 拥有最高权限,[S]、[E]、[A] 都是被主密钥 [C] 认证过的「子密钥」,只将子密钥写入 Canokey 中,主密钥和撤销证书使用其他不联网的介质保存,这个介质可以是物理上绝对安全的多个 U盘、CD……
生成主密钥 #
先输入下面命令生成主密钥
gpg --expert --full-gen-key
输入 11
选择生成自定义用途的 ECC
密钥
gpg (GnuPG) 2.3.4; Copyright (C) 2021 g10 Code GmbH
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) # DSA 算法(仅用于签名)
(4) RSA (sign only) # RSA 算法(仅用于签名)
(7) DSA (set your own capabilities) # DSA 算法(自定义用途)
(8) RSA (set your own capabilities) # RSA 算法(自定义用途)
(9) ECC (sign and encrypt) *default* # ECC 算法(用于签名和加密)*默认
(10) ECC (sign only) # ECC 算法(仅用于签名)
(11) ECC (set your own capabilities) # ECC 算法(自定义用途)
(13) Existing key # 现有的密钥
(14) Existing key from card # 智能卡中现有的密钥
Your selection? 11
接下来会选择密钥的功能,对于主密钥,[C] 是必须的,此处并没有取消主密钥的签名功能,你可以输入 S 取消签名功能
# ECDSA/EdDSA 密钥的可实现的功能: 签名(Sign) 认证(Certify) 身份验证(Authenticate)
Possible actions for this ECC key: Sign Certify Authenticate
Current allowed actions: Sign Certify # 目前启用的功能: 签名(Sign) 认证(Certify
(S) Toggle the sign capability # 签名功能开关
(A) Toggle the authenticate capability # 身份验证功能开关
(Q) Finished # 已完成
Your selection? Q
选择 ECC 密钥使用的「椭圆曲线」加密算法
Please select which elliptic curve you want: # 请选择您想要使用的椭圆曲线:
(1) Curve 25519 *default* # 默认
(2) Curve 448
(3) NIST P-256
(4) NIST P-384
(5) NIST P-521
(6) Brainpool P-256
(7) Brainpool P-384
(8) Brainpool P-512
(9) secp256k1
Your selection? 1 # 推荐 Curve 25519
输入密钥有效期以及用户标识信息
Please specify how long the key should be valid. # 请设定这个密钥的有效期限
0 = key does not expire # 密钥永不过期
<n> = key expires in n days # 密钥在 n 天后过期
<n>w = key expires in n weeks # 密钥在 n 周后过期
<n>m = key expires in n months # 密钥在 n 月后过期
<n>y = key expires in n years # 密钥在 n 年后过期
Key is valid for? (0) 0 # 我比较懒,主密钥设置的永不过期
Key does not expire at all # 密钥永远不会过期
Is this correct? (y/N) y # 这些内容正确吗? (y/N) y
# GnuPG 需要构建用户标识以辨认您的密钥
GnuPG needs to construct a user ID to identify your key.
Real name: Xxx # 真实姓名: Xxx
Email address: xxx@xxx.com # 电子邮件地址: xxx@xxx.com
Comment: # 注释:
You selected this USER-ID: # 您选定了此用户标识:
"Xxx <xxx@xxx.com>"
# 更改姓名(N)、注释(C)、电子邮件地址(E)或确定(O)/退出(Q)? O
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.
# C://Scoop//apps//gpg//current//home/trustdb.gpg:建立了信任度数据库
gpg: C://Scoop//apps//gpg//current//home/trustdb.gpg: trustdb created
# 密钥 MASTERKEYID12345 被标记为绝对信任
gpg: key MASTERKEYID12345 marked as ultimately trusted
gpg: directory 'C://Scoop//apps//gpg//current//home/openpgp-revocs.d' created
# 吊销证书已被存储为 'C://Scoop//apps//gpg//current//home/openpgp-revocs.d/DB32C2542C0939ADEDEAF078MASTERKEYID12345.rev'
gpg: revocation certificate stored as 'C://Scoop//apps//gpg//current//home/openpgp-revocs.d/DB32C2542C0939ADEDEAF078MASTERKEYID12345.rev'
public and secret key created and signed.
Note that this key cannot be used for encryption. You may want to use
the command "--edit-key" to generate a subkey for this purpose.
pub ed25519 2022-01-08 [SC]
DB32C2542C0939ADEDEAF078MASTERKEYID12345 # 密钥指纹 fingerprint
uid Xxx <xxx@xxx.com>
# 生成过程中会要求输入一个密码(passphrase)来保护主密钥的私钥,这个密码不要太简单
┌─────────────────────────────────────────────────────┐
│ Please enter the passphrase to │
│ protect your newkey │
│ │
│ Passphrase:_______________________________________ │
│ │
│ <OK> <Cancel> │
└─────────────────────────────────────────────────────┘
默认会生成一份「吊销证书」请妥善备份
生成吊销证书 #
也可以手动生成吊销证书,所谓「吊销证书」即用来吊销某个密钥,表示该密钥因为某些原因不再使用了。
gpg --gen-revoke -ao master-revoke.rv [用户ID] # 此过程会要求输入前面设置的主密钥私钥的密码(passphrase)
# 比如上面示例的 Xxx <xxx@xxx.com>
gpg --gen-revoke -ao master-revoke.rv xxx@xxx.com
# 输出类似下面
sec ed25519/MASTERKEYID12345 2022-01-08 Xxx <xxx@xxx.com>
要为这个密钥创建一个吊销证书吗?(y/N) y
请选择吊销的原因:
0 = 未指定原因
1 = 密钥已泄漏
2 = 密钥被替换
3 = 密钥不再使用
Q = 取消
(也许您会想要在这里选择 1)
您的决定是什么? 3
请输入描述(可选);以空白行结束:
>
吊销原因:密钥不再使用
(未给定描述)
这样可以吗? (y/N) y
已创建吊销证书。
请把这个文件转移到一个您可以藏起来的介质上;如果坏人获取到了这
份证书的话,那么他就能使用它并让您的密钥无法继续使用。把此证书
打印出来再存放到安全的地方也是很好的方法,以免您的保存媒体变得
不可读。但是千万小心:您机器上的打印系统可能会在打印过程中储存
这些数据,并使得其他人看到!
设置主 UID #
# 用法:gpg --quick-set-primary-uid [keyid/fingerprint] [uid],比如:
gpg --quick-set-primary-uid MASTERKEYID12345 'xxx <xxx@xxx.com>'
生成子密钥 #
Canokey 由于芯片性能限制,支持在密钥上直接生成的算法类型有所限制,并且在硬件密钥上直接生成也不方便备份,因此建议先在当前计算机上生成、备份后再转移到 Canokey 上。
下面分别生成 Signature, Encryption, Authentication 三种类型的子密钥
# 使用专家模式编辑刚才生成的主密钥
gpg --expert --edit-key [keyid/fingerprint]
# 比如上面演示中的密钥主密钥 MASTERKEYID12345
gpg --expert --edit-key MASTERKEYID12345
gpg (GnuPG) 2.3.4; Copyright (C) 2021 g10 Code GmbH
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 ed25519/MASTERKEYID12345
created: 2022-01-08 expires: never usage: SC
trust: ultimate validity: ultimate
[ultimate] (1). Xxx <xxx@xxx.com>
生成 Signature key #
# 开始生成 Signature key 用于签名的子密钥
gpg> addkey
Please select what kind of key you want:
(1) RSA and RSA
(2) DSA and Elgamal
(3) DSA (sign only) # DSA 算法(仅用于签名)
(4) RSA (sign only) # RSA 算法(仅用于签名)
(7) DSA (set your own capabilities) # DSA 算法(自定义用途)
(8) RSA (set your own capabilities) # RSA 算法(自定义用途)
(9) ECC (sign and encrypt) *default* # ECC 算法(用于签名和加密)*默认
(10) ECC (sign only) # ECC 算法(仅用于签名)
(11) ECC (set your own capabilities) # ECC 算法(自定义用途)
(13) Existing key # 现有的密钥
(14) Existing key from card # 智能卡中现有的密钥
Your selection? 10 # 选择 ECC 仅用于签名
Please select which elliptic curve you want: # 请选择您想要使用的椭圆曲线:
(1) Curve 25519 *default* # 默认
(2) Curve 448
(3) NIST P-256
(4) NIST P-384
(5) NIST P-521
(6) Brainpool P-256
(7) Brainpool P-384
(8) Brainpool P-512
(9) secp256k1
Your selection? 1 # 推荐 Curve 25519
Please specify how long the key should be valid. # 请设定这个密钥的有效期限
0 = key does not expire # 密钥永不过期
<n> = key expires in n days # 密钥在 n 天后过期
<n>w = key expires in n weeks # 密钥在 n 周后过期
<n>m = key expires in n months # 密钥在 n 月后过期
<n>y = key expires in n years # 密钥在 n 年后过期
Key is valid for? (0) 0 # 我设置的是 10 年
Key does not expire at all # 密钥永远不会过期
Is this correct? (y/N) y # 这些内容正确吗? (y/N) y
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.
sec ed25519/MASTERKEYID12345
created: 2022-01-08 expires: never usage: SC
trust: ultimate validity: ultimate
ssb ed25519/SIGNATUREKEYID67
created: 2022-01-08 expires: 2032-01-06 usage: S
[ ultimate ] (1). Xxx <xxx@xxx.com>
gpg> save # 生成结束一定要记得输入 save 保存!
生成 Encryption key #
类似上面生成 Signature key 子密钥的过程,Encryption key 只给 [E] 功能
sec ed25519/MASTERKEYID12345
created: 2022-01-08 expires: never usage: SC
trust: ultimate validity: ultimate
ssb ed25519/SIGNATUREKEYID67
created: 2022-01-08 expires: 2032-01-06 usage: S
ssb cv25519/ENCRYPTIONKEYID8
created: 2022-01-08 expires: 2032-01-06 usage: E
[ ultimate ] (1). Xxx <xxx@xxx.com>
生成 Authentication key #
类似上面生成 Signature key 子密钥的过程,Authentication key 只给 [A] 功能
sec ed25519/MASTERKEYID12345 # 主密钥 [SC]
created: 2022-01-08 expires: never usage: SC
trust: ultimate validity: ultimate
ssb ed25519/SIGNATUREKEYID67 # 子密钥 Signature key
created: 2022-01-08 expires: 2032-01-06 usage: S
ssb cv25519/ENCRYPTIONKEYID8 # 子密钥 Encryption key
created: 2022-01-08 expires: 2032-01-06 usage: E
ssb ed25519/AUTHENTICATION90 # 子密钥 Authentication key
created: 2022-01-08 expires: 2032-01-06 usage: A
[ ultimate ] (1). Xxx <xxx@xxx.com>
列出所有的 Key #
# 列出所有的 key 信息
gpg --fingerprint -K --keyid-format LONG
C:\Scoop\apps\gpg\current\home\pubring.kbx
------------------------------------------
sec ed25519/MASTERKEYID12345 2022-01-08 [SC]
Key fingerprint = DB32 C254 2C09 39AD EDEA F078 MAST ERKE YID1 2345
uid [ ultimate] Xxx <xxx@xxx.com>
ssb ed25519/SIGNATUREKEYID67 2022-01-08 [S] [expires: 2032-01-06]
ssb cv25519/ENCRYPTIONKEYID8 2022-01-08 [E] [expires: 2032-01-06]
ssb ed25519/AUTHENTICATION90 2022-01-08 [A] [expires: 2032-01-06]
这时候生成 Key 的过程就结束啦~
备份 Key 的各种信息 #
将三种子密钥转移到 Canokey 之前,建议备份一下一些原始密钥信息到安全地存储介质中
# 导出主密钥公钥 master-pub-key.pgp
gpg -ao master-pub-key.pgp --export [主密钥ID]
# 导出主密钥公钥
gpg -ao sign-pub-key.pgp --export [签名子密钥ID]
gpg -ao encrypt-pub-key.pgp --export [加密子密钥ID]
gpg -ao authenticate-pub-key.pgp --export [认证子密钥ID]
# 导出私钥信息
gpg -ao master-secret-key.pgp --export-secret-key [主密钥ID] # 主密钥私钥信息,需要绝对安全的保存
gpg -ao sign-secret-key.pgp --export-secret-key [签名子密钥ID]
gpg -ao encrypt-secret-key.pgp --export-secret-key [加密子密钥ID]
gpg -ao authenticate-secret-key.pgp --export-secret-key [认证子密钥ID]
将子密钥写入 Canokey #
Canokey 的 OpenPGP 应用和 Yubikey 一样,初始 PIN 为:
- 默认
PIN
:123456
- 默认
Admin PIN
:12345678
将 Canokey 插入计算机,开始写入密钥
gpg --card-status # 查看智能卡状态
Reader ...........: canokeys.org OpenPGP PIV OATH 0
Application ID ...: C123001234123456B1C001111B123400
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: CanoKeys
Serial number ....: 01232A56
Name of cardholder: [not set]
Language prefs ...: [not set]
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 64 64 64
PIN retry counter : 3 0 3
Signature counter : 0
UIF setting ......: Sign=off Decrypt=off Auth=off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
分别写入 Signature, Encryption, Authentication 三种子密钥到对应的 OpenPGP 应用卡槽内
gpg --expert --edit-key MASTERKEYID12345
gpg (GnuPG) 2.3.4; Copyright (C) 2021 g10 Code GmbH
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 ed25519/MASTERKEYID12345 # 主密钥 [SC]
created: 2022-01-08 expires: never usage: SC
trust: ultimate validity: ultimate
ssb ed25519/SIGNATUREKEYID67 # 子密钥 Signature key
created: 2022-01-08 expires: 2032-01-06 usage: S
ssb cv25519/ENCRYPTIONKEYID8 # 子密钥 Encryption key
created: 2022-01-08 expires: 2032-01-06 usage: E
ssb ed25519/AUTHENTICATION90 # 子密钥 Authentication key
created: 2022-01-08 expires: 2032-01-06 usage: A
[ ultimate ] (1). Xxx <xxx@xxx.com>
gpg> key 1 # 选择第一个子密钥[S]
sec ed25519/MASTERKEYID12345
created: 2022-01-08 expires: never usage: SC
trust: ultimate validity: ultimate
ssb* ed25519/SIGNATUREKEYID67 # ssb 后面有个*表示这个 key 被选中了
created: 2022-01-08 expires: 2032-01-06 usage: S
ssb cv25519/ENCRYPTIONKEYID8
created: 2022-01-08 expires: 2032-01-06 usage: E
ssb ed25519/AUTHENTICATION90
created: 2022-01-08 expires: 2032-01-06 usage: A
[ ultimate ] (1). Xxx <xxx@xxx.com>
gpg> keytocard # 将密钥写入 Canokey
Please select where to store the key: # 请选择在哪里存储密钥
(1) Signature key # 签名密钥
(3) Authentication key # 身份验证密钥
Your selection? 1 # 将[S]密钥写入 Canokey 的 Signature key 区域
# 会要求输入解锁主密钥私钥保护的密码(passphrase)以及 Canokey 的 Admin PIN
# 写完 Signature key 后继续写入其他子密钥
gpg> key 1 # 取消选择第一个子密钥
sec ed25519/MASTERKEYID12345
created: 2022-01-08 expires: never usage: SC
trust: ultimate validity: ultimate
ssb ed25519/SIGNATUREKEYID67
created: 2022-01-08 expires: 2032-01-06 usage: S
ssb cv25519/ENCRYPTIONKEYID8
created: 2022-01-08 expires: 2032-01-06 usage: E
ssb ed25519/AUTHENTICATION90
created: 2022-01-08 expires: 2032-01-06 usage: A
[ ultimate ] (1). Xxx <xxx@xxx.com>
gpg> key 2 # 选择第二个子密钥[E]
sec ed25519/MASTERKEYID12345
created: 2022-01-08 expires: never usage: SC
trust: ultimate validity: ultimate
ssb ed25519/SIGNATUREKEYID67
created: 2022-01-08 expires: 2032-01-06 usage: S
ssb* cv25519/ENCRYPTIONKEYID8 # ssb 后面有个*表示这个 key 被选中了
created: 2022-01-08 expires: 2032-01-06 usage: E
ssb ed25519/AUTHENTICATION90
created: 2022-01-08 expires: 2032-01-06 usage: A
[ ultimate ] (1). Xxx <xxx@xxx.com>
gpg> keytocard # 将密钥写入 Canokey
Please select where to store the key: # 请选择在哪里存储密钥
(2) Encryption key # 加密密钥
Your selection? 2 # 将[E]密钥写入 Canokey 的 Encryption key 区域
gpg> key 2 # 取消选择第二个子密钥
sec ed25519/MASTERKEYID12345
created: 2022-01-08 expires: never usage: SC
trust: ultimate validity: ultimate
ssb ed25519/SIGNATUREKEYID67
created: 2022-01-08 expires: 2032-01-06 usage: S
ssb cv25519/ENCRYPTIONKEYID8
created: 2022-01-08 expires: 2032-01-06 usage: E
ssb ed25519/AUTHENTICATION90
created: 2022-01-08 expires: 2032-01-06 usage: A
[ ultimate ] (1). Xxx <xxx@xxx.com>
gpg> key 3 # 选择第三个子密钥[A]
sec ed25519/MASTERKEYID12345
created: 2022-01-08 expires: never usage: SC
trust: ultimate validity: ultimate
ssb ed25519/SIGNATUREKEYID67
created: 2022-01-08 expires: 2032-01-06 usage: S
ssb cv25519/ENCRYPTIONKEYID8
created: 2022-01-08 expires: 2032-01-06 usage: E
ssb* ed25519/AUTHENTICATION90 # ssb 后面有个*表示这个 key 被选中了
created: 2022-01-08 expires: 2032-01-06 usage: A
[ ultimate ] (1). Xxx <xxx@xxx.com>
gpg> keytocard # 将密钥写入 Canokey
Please select where to store the key: # 请选择在哪里存储密钥
(3) Authentication key # 身份认证密钥
Your selection? 2 # 将[E]密钥写入 Canokey 的 Authentication key 区域
# 最后保存,写入完成
gpg> save # 千万不要忘记这步!!!
写入完成后,验证一下
gpg --card-status # 查看智能卡状态
Reader ...........: canokeys.org OpenPGP PIV OATH 0
Application ID ...: C123001234123456B1C001111B123400
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: CanoKeys
Serial number ....: 01232A56
Name of cardholder: [not set]
Language prefs ...: [not set]
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 64 64 64
PIN retry counter : 3 0 3
Signature counter : 0
UIF setting ......: Sign=off Decrypt=off Auth=off
Signature key ....: AB11 7854 7543 3456 8SF6 A43F SIGN ATUR EKEY ID67
created ....: 2022-01-08 02:12:00
Encryption key....: 1298 ABCD 7527 3849 8743 6A94 ENCR YPTI ONKE YID8
created ....: 2022-01-08 02:13:31
Authentication key: 5839 7365 9217 8482 0987 AA06 AUTH ENTI CATI ON90
created ....: 2022-01-08 02:14:08
General key info..: sub ed25519/AB85E2D677CA9A84 2022-01-08 Xxx <xxx@xxx.com>
sec ed25519/MASTERKEYID12345 created: 2022-01-08 expires: never
ssb> ed25519/SIGNATUREKEYID67 created: 2022-01-08 expires: 2032-01-06 # ssb后面的>表示密钥已经转移到卡内
card-no: F1D0 01234A34
ssb> cv25519/ENCRYPTIONKEYID8 created: 2022-01-08 expires: 2032-01-06 # ssb后面的>表示密钥已经转移到卡内
card-no: F1D0 01234A34
ssb> ed25519/AUTHENTICATION90 created: 2022-01-08 expires: 2032-01-06 # ssb后面的>表示密钥已经转移到卡内
card-no: F1D0 01234A34
现在所有密钥就已经正确的写入到 Canokey 里面了
Canokey 为 GitHub 提交签名 #
将 Signature key
对应的 GPG 公钥添加到 GitHub GPG keys 里,签名的时候触摸一下 Canokey 或者输入 PIN 即可解锁私钥的访问。
# 设置 gpg 程序的路径
git config --global gpg.program "C:/Scoop/apps/gnupg/current/bin/gpg.exe"
# 类似于“指针”将 key 指向 Canokey 上
gpg --card-status
# 指定用于 git 提交时签名的 GPG key
git config --global user.signingkey SIGNATUREKEYID67 # Signature keyid
# 以后提交的时候加上 -S 参数进行 GPG 签名,比如
git commit -S -m "first commit"
# 强制当前仓库使用 GPG key 签名
git config commit.gpgsign true
# 强制全局使用 GPG key 签名
git config --global commit.gpgsign true
# 强制 GPG key 签名后提交时就不需要加 -S 参数了,比如
git commit -m "second commit"
# 查看 git 提交时的签名信息
git log --show-signature
Canokey 用来 SSH 登录 #
前面生成的 OpenPGP 的 Authentication key
是不能直接用在 SSH 认证登录上的,如果我们想用 Canokey 的 Authentication key
登录 GitHub 或者服务器,还需要一点操作,因为 Linux 和 macOS 下几乎是开箱即用的状态,我这里只说下 Windows 下的两种比较简单的方案,两种方式可以根据自己实际需求选择一种使用即可
使用 win-gpg-agent 处理[推荐] #
win-gpg-agent 是一组开源的简单工具,使用 Golang 编写,它可以让我们在 Windows 10/11 上能更加轻松地使用 GPG 和 SSH
# 安装 win-gpg-agent
scoop bucket add extras
scoop install sudo win-gpg-agent
# 停止 Windows 自带的 SSH 服务
sudo Stop-Service ssh-agent
sudo Set-Service -StartupType Disabled ssh-agent
对应你的 Scoop 安装软件的 实际路径,修改配置文件 C:\Scoop\apps\win-gpg-agent\1.6.0\agent-gui.conf
# 我的配置文件修改如下
gpg:
install_path: "${SystemDrive}\\Scoop\\apps\\gnupg\\current"
# Before gnupg 2.3.2 release home directory could be properly link-ed
# homedir: "${USERPROFILE}\\Scoop\\apps\\gnupg\\current\\home"
# With gnupg 2.3.3 release (due to the changes in T5537) use this instead
# homedir: "${USERPROFILE}\\Scoop\\persist\\gnupg\\home"
# socketdir: ""
# After gnupg 2.3.4 release we have to switch to
homedir: "${SystemDrive}\\Scoop\\apps\\gnupg\\current\\home"
socketdir: "${SystemDrive}\\Scoop\\apps\\gnupg\\current\\gnupg"
gui:
debug: false
setenv: true
openssh: native
# Use line below to enable SSH_AUTH_SOCK to point to cygwin socket
# openssh: cygwin
上面的 ${SystemDrive}
代表系统盘盘符(比如:C:
),${USERPROFILE}
代表用户目录(比如:C:\Users\username
)
将 Canokey 插入计算机,运行 win-gpg-agent
程序,打开终端
# 刷新智能卡状态
gpg --card-status
# 查看用于 SSH 的子密钥的公钥信息
ssh-add -L # 下面是输出
ssh-ed25519 AAAAD4G5xKKpgMDvVktSNTpQhASYNS591AKW9jOaNk2eJzuWQCCAAIE5aTx1lZDII/GA cardno:F1D0 01232A56
将输出的 ssh-ed25519
这行信息复制保存到 GitHub 的 SSH keys (或者其他需要登录的服务器)的信任公钥里即可,可以测试一下自己的私有仓库,出现 Pinentry (go) 弹窗输入 PIN 解锁智能卡即可
设置下 win-gpg-agent 开机自动运行,组合键 Win + R 打开 运行
输入命令 shell:startup
进入启动项目录,新建一个快捷方式指向 win-gpg-agent
想要通过 WSL、Cygwin、MSYS2、win32-openssh 等工具来使用 Canokey 等智能卡的 OpenPGP 应用的 SSH 功能,可参考 win-gpg-agent 文档
使用 PuTTY 处理[备选] #
在 Windows 下使用 PuTTY 来处理 SSH Agent 也是个不错的方案,但是可能比较复杂一点
# 类似于“指针”将 key 指向 Canokey 上
gpg --card-status
# 终端进入 GPG 的工作目录,Scoop 安装的 GPG 默认工作目录为:C:\Scoop\apps\gnupg\current\home
cd C:\Scoop\apps\gnupg\current\home
# 编辑 GPG 配置文件(没安装 vim 就手动新建/编辑)
vim gpg-agent.conf
# 加入以下内容并保存
enable-putty-support
enable-ssh-support
default-cache-ttl 600
max-cache-ttl 7200
# 更改 git 设置,使用 PuTTY pageant 处理 SSH
git config --global core.sshcommand 'plink -agent'
# 查看 GPG 密钥的 Keygrip
gpg -K --with-keygrip
# 复制 Authentication key 的 Keygrip 数值(一串数字)
vim sshcontrol
# 将 Authentication key 的 Keygrip 数值写入 sshcontrol 文件里保存
# 关闭 gpg-agent
gpg-connect-agent killagent /bye
# 开启 gpg-agent
gpg-connect-agent /bye
# 现在列出公钥
gpg --list-public-keys
C:\Scoop\apps\gnupg\current\home\pubring.kbx
------------------------------------------
pub ed25519 2022-01-08 [SC]
23ABCD638264ADC9483FE09A53857534534CA5B6
uid [ultimate] Xxx <xxx@xxx.com>
sub ed25519 2022-01-08 [S] [expires: 2032-01-06]
sub cv25519 2022-01-08 [E] [expires: 2032-01-06]
sub ed25519 2022-01-08 [A] [expires: 2032-01-06]
# 导出公钥为 SSH 的公钥格式
gpg --export-ssh-key
ssh-ed25519 AAAAD4G5xKKpgMDvVktSNTpQhASYNS591AKW9jOaNk2eJzuWQCCAAIE5aTx1lZDII/GA openpgp:0x3CF3456E
将 ssh-ed25519
开头的这行内容完整地添加到 GitHub 的 SSH keys 里(其他服务器如 Linux SSH 远程访问同理),SSH 登陆的时候触摸一下 Canokey 或者输入 PIN 即可(根据设置的不同策略)
以 GitHub 为例,假设你本地已经配置好 Git 的参数,可以在终端里先手动尝试下使用 PuTTY pageant :plink.exe -agent -v git@github.com
如果是自己常用的计算机点击 Accept
接受,以后使用时,PuTTY 会将请求转发给 GPG,GPG 会提示您输入 PIN 并使用 Canokey/YubiKey 登录
更换电脑/重装系统后恢复 #
在新的系统上,只需要:
# 安装好所需软件后,导入公钥到计算机
gpg --import master-pub-key.pgp
# 信任主密钥
gpg --expert --edit-key [主密钥id/fingerprint]
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 # 完全信任
Do you really want to set this key to ultimate trust? (y/N) y # 确认
gpg> save # 最后记得保存
gpg> quit # 退出
# 完成后记得重启下 GPG Agent
gpg-connect-agent killagent /bye
gpg-connect-agent /bye
插入 Canokey/Yubikey
# 查看智能卡状态
gpg --card-status
# 编辑卡片设置
gpg --card-edit
gpg/card> fetch # 将子密钥指向 Canokey
gpg/card> quit # 退出
验证
gpg --card-status # 查看智能卡状态
Reader ...........: canokeys.org OpenPGP PIV OATH 0
Application ID ...: C123001234123456B1C001111B123400
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: CanoKeys
Serial number ....: 01232A56
Name of cardholder: [not set]
Language prefs ...: [not set]
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 64 64 64
PIN retry counter : 3 0 3
Signature counter : 0
UIF setting ......: Sign=off Decrypt=off Auth=off
Signature key ....: AB11 7854 7543 3456 8SF6 A43F SIGN ATUR EKEY ID67
created ....: 2022-01-08 02:12:00
Encryption key....: 1298 ABCD 7527 3849 8743 6A94 ENCR YPTI ONKE YID8
created ....: 2022-01-08 02:13:31
Authentication key: 5839 7365 9217 8482 0987 AA06 AUTH ENTI CATI ON90
created ....: 2022-01-08 02:14:08
General key info..: sub ed25519/AB85E2D677CA9A84 2022-01-08 Xxx <xxx@xxx.com>
sec# ed25519/MASTERKEYID12345 created: 2022-01-08 expires: never # sec后面的#表示主密钥的私钥不在此计算机上,这是安全的
ssb> ed25519/SIGNATUREKEYID67 created: 2022-01-08 expires: 2032-01-06 # ssb后面的>表示密钥已经转移到卡内
card-no: F1D0 01234A34
ssb> cv25519/ENCRYPTIONKEYID8 created: 2022-01-08 expires: 2032-01-06 # ssb后面的>表示密钥已经转移到卡内
card-no: F1D0 01234A34
ssb> ed25519/AUTHENTICATION90 created: 2022-01-08 expires: 2032-01-06 # ssb后面的>表示密钥已经转移到卡内
card-no: F1D0 01234A34
设置 GPG 命令别名 #
在 Windows 下的 PowerShell 里可以使用别名来简化 GPG 相关的命令(添加到用户的 PowerShell 配置文件)
# GPG for Canokeys: https://dejavu.moe/posts/canokey-openpgp/
# 终止 gpg-agent 命令别名: killgpg
function killgpg{gpg-connect-agent killagent /bye}
# 启动 gpg-agent 命令别名: startgpg
function startgpg{gpg-connect-agent /bye}
# 查看 gpg 智能卡状态 命令别名: card
function card{gpg --card-status}
文中信息都已脱敏处理,本文篇幅比较长,由于之前自己生成的过程中记录的比较乱,难免存在少部分可能不准确或者错误的地方,欢迎指正。
参考资料: