前言#
最近因为工作原因入手了一个 Canokey,想要利用起来,功能很多,除了 PIV 平时用不到,OpenPGP 用起来比较麻烦一点,其他几个功能用起来十分简单。因此想记下来,顺带当自己的备忘录了。
准备#
首先说一下,本文环境主要是在 Windows 下,其他系统可以进行参考。
- Gpg4win(同时会安装 Kleopatra,安装 Gpg4win 时勾选 Kleopatra 即可)
- 一个支持 OpenPGP 的硬件密钥(如果只是想在本地使用可以不需要)
开始之前#
我们需要清楚 OpenPGP 和 GPG 的区别:
OpenPGP 它只是一种标准,定义了一种密钥规范,而 GPG 是一种工具,可以实现与 OpenPGP 密钥的交互和操作。他们的关系就好像一份食谱和一位厨师,OpenPGP 就是食谱,而 GPG 是这位厨师,固定的一份食谱,它的实现是需要一位厨师的,而有很多厨师都可以实现这一份食谱,而 GPG 就是其中名气最大的一位。而 Gpg4win 就只是厨师换了套衣服,它的核心还是这位厨师 GPG。
其次 OpenPGP 推崇权限最小化原则,因此 OpenPGP 密钥一般是由一个主密钥下分别创建多个子密钥,并且主密钥只有签发功能,而其他功能都交由子密钥,子密钥的功能可以在创建时指定。
并且 OpenPGP 密钥是成对出现的,有公钥和私钥,就像我们常见的 OpenSSL 密钥 和 OpenSSH 密钥。但一般情况下我们不会使用子密钥的公钥,因为公钥可以公开,并且子密钥的公钥是被包括在公钥的子密钥中的,没必要单独公开子密钥的公钥。
关于私钥,一个 OpenPGP 密钥可以拥有 4 种功能,并且一个子密钥可以同时拥有多个功能。分别是 S - Sign(签名)、E - Encrypt(Encr、加密)、A - Authenticate(Auth,认证)和 C - Certify(Cert,签发)。他们对应的功能如下表:
| 功能 | 标记 | 用途 |
|---|---|---|
| Sign(签名) | S | 给自己的应用、代码、git 提交等签名等 |
| Encrypt(加密) | E | 加密文本、文件等 |
| Authenticate(认证) | A | 身份认证,一般用于 SSH 登录 |
| Certify(签发) | C | 由主密钥给自己签发新的子密钥。或者给认证他人的公钥来构建信任网络 |
开始#
首先确认安装好 gpg4win,在终端输入 gpg --version即可确认。

生成主密钥#
使用 gpg --expert --full-gen-key生成主密钥对,其中 --full-gen-key的作用是提供更多的选项。
> gpg --expert --full-gen-key # 生成主密钥对
gpg (GnuPG) 2.4.8; Copyright (C) 2025 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)
(4) RSA (sign only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(9) ECC (sign and encrypt) *default*
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(13) Existing key
(14) Existing key from card
Your selection? 11 # 选择"11",使用可以自定义功能的 ECC 算法
接下来定制主密钥对:
Possible actions for this ECC key: Sign Certify Authenticate
Current allowed actions: Sign Certify # 现在密钥的功能:签名 和 认证
(S) Toggle the sign capability # 切换 sign 功能状态
(A) Toggle the authenticate capability # 切换 auth 功能状态
(Q) Finished # 结束进行下一步
Your selection? s # 关闭 sign 功能,只保留 cert 功能
...省略部分
Your selection? q # 进行下一步
接下来选择主密钥的加密算法和期限:
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 # 选择第一个默认 Curve25519 椭圆算法
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 # 因为选了永不过期,会确认是否正确
新密钥会需要 UID,用于标记这个密钥是谁的,接下来会有 GUI 需要你设定密钥密码,需要大于 8 位:
GnuPG needs to construct a user ID to identify your key.
Real name: Zhang San # 密钥持有者姓名,注意,如果需要用于 git commit 的认证需要与 github 账户名相同
Email address: zhang.san@example.com # 密钥持有者邮箱,注意,如果需要用于 git commit 的认证需要与 github 邮箱相同
Comment: xxxxx # 备注,可选
You selected this USER-ID:
"Zhang San (xxxxx) <zhang.san@example.com>"
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.
gpg: revocation certificate stored as 'C:\\Users\\username\\AppData\\Roaming\\gnupg\\openpgp-revocs.d\\ABCDEF0123456789ABCDEF1234567890ABCDEF12.rev' # 同时生成的吊销证书位置
public and secret key created and signed.
pub ed25519 2025-12-06 [C] # 密钥算法,生成日期,拥有的功能[C]签发
ABCDEF0123456789ABCDEF1234567890ABCDEF12 # 密钥指纹
uid Zhang San (xxxxx) <zhang.san@example.com> # 密钥的 UID
生成子密钥#
我们先查看一下自己的电脑上的密钥,使用gpg --fingerprint --keyid-format long -K,可以看到一个私钥都没有,UID下是空的:
> gpg --fingerprint --keyid-format long -K
[keyboxd]
---------
sec ed25519/34567890ABCDEF12 2025-12-06 [C] # '34567890ABCDEF12'是长指纹后 16 位,可以代替长指纹使用
Key fingerprint = ABCD EF12 3456 7890 ABCD EF12 3456 7890 ABCD EF12
uid [ultimate] Zhang San (xxxxx) <zhang.san@example.com> # [ultimate] 指你的电脑绝对信任此 UID,毕竟是在这里创建的
ABCDEF12...ABCDEF12记得换为自己的,可以只使用 16 位短格式,及长指纹的后16位快速生成三个功能的子密钥,他们的功能分别是签名、加密、认证,其中除了加密由于用于密钥交互不能使用ed25519,故使用的是cv25519椭圆算法,其余都是ed25519:
gpg --quick-add-key ABCDEF0123456789ABCDEF1234567890ABCDEF12 ed25519 sign
gpg --quick-add-key ABCDEF0123456789ABCDEF1234567890ABCDEF12 cv25519 encr
gpg --quick-add-key ABCDEF0123456789ABCDEF1234567890ABCDEF12 ed25519 auth
接下来我们再次查看电脑下面存放的私钥,可以看到我们的主密钥下面有三个子密钥(-K已经指定了查看的为私钥状态):
> gpg --fingerprint --keyid-format long -K
[keyboxd]
---------
sec ed25519/34567890ABCDEF12 2025-12-06 [C] # 'sec'指主密钥的私钥
Key fingerprint = ABCD EF12 3456 7890 ABCD EF12 3456 7890 ABCD EF12
uid [ultimate] Zhang San (xxxxx) <zhang.san@example.com>
ssb ed25519/01234567890ABCDE 2025-12-06 [S] # 'ssb'指子密钥的私钥,功能[S]签名
ssb cv25519/0E1234567890ABCD 2025-12-06 [E] # 功能[E]加密
ssb ed25519/0AABCDEF09876543 2025-12-06 [A] # 功能[A]认证
备份密钥#
因为将密钥转入卡会删除本地密钥,并且无法导出,所以需要在转入卡之前先导出密钥。
导出主公钥:
#gpg -ao <文件名,随自己喜好> --export <主密钥指纹>
gpg -ao ZhangSan_0xABCDEF12_public.pub --export 34567890ABCDEF12
导出私钥,注意,使用了!指定指导出对应私钥:
# 主私钥
gpg -ao ZhangSan_0xABCDEF12_SECRET.asc --export-secret-key 34567890ABCDEF12!
# 子私钥
gpg -ao ZhangSan_0xABCDEF12_SIGN.asc --export-secret-key 01234567890ABCDE!
gpg -ao ZhangSan_0xABCDEF12_ENCR.asc --export-secret-key 0E1234567890ABCD!
gpg -ao ZhangSan_0xABCDEF12_AUTH.asc --export-secret-key 0AABCDEF09876543!
导出完整密钥链:
gpg -ao ZhangSan_0xABCDEF12_ALL.asc --export-secret-keys
开始导入到硬件密钥#
如果是新的硬件密钥需要先编辑 Card 信息,首先使用gpg --card-status查看:
> gpg --card-status # 查看卡信息
Reader ...........: canokeys.org OpenPGP PIV OATH 0
Application ID ...: C0987654321FEDCBA0987654321FEDCB
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: CanoKeys
Serial number ....: 0131313A
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]
可以看到都是空的,使用gpg --card-edit进行修改:
> gpg --card-edit
Reader ...........: canokeys.org OpenPGP PIV OATH 0
Application ID ...: C0987654321FEDCBA0987654321FEDCB
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: CanoKeys
Serial number ....: 0131313A
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]
gpg/card> admin # 使用 admin 进入管理模式
Admin commands are allowed
gpg/card> passwd
gpg: OpenPGP card no. C0987654321FEDCBA0987654321FEDCB detected
1 - change PIN # 修改 PIN
2 - unblock PIN # 修改解锁 PIN。注意!修改时会让 Pin 也变为 unblock PIN
3 - change Admin PIN # 修改管理员 PIN
4 - set the Reset Code # 修改重置码,一般不用改
Q - quit
Your selection? 3 # 修改管理员 PIN (默认为 12345678)
...
Your selection? 2 # 修改解锁码,需要先输入管理员 PIN
...
Your selection? 1 # 修改 PIN 码,如果你是像我一样先修改了解锁码现在的 PIN 码就是解锁码,没有修改解锁码的话就是默认的 123456
...
Your selection? q # 退出密码修改
gpg/card> name # 修改卡持有者姓名
Cardholder's surname: Zhang # 姓
Cardholder's given name: San # 名
gpg/card> login # 修改卡持有者登录名
Login data (account name): ZhangSan
gpg/card> uif # 查看如何修改 UIF 信息
usage: uif N [on|off|permanent]
1 <= N <= 3
gpg/card> uif 1 on # 开启 Sign 的触摸策略
gpg/card> uif 3 on # 开启 Auth 的触摸策略
gpg/card> sex # 修改卡持有者性别
Salutation (M = Mr., F = Ms., or space): m # M 为男,F 为女,空格置空
gpg/card> lang # 修改卡持有者使用语言
Language preferences: zh # zh 中文
gpg/card> url # 修改卡持有者 GPG 公钥发布网址
URL to retrieve public key: https://www.hetong-re4per.com/HeTongRe4per.pub # 这里我填的我自己的
gpg/card> list # 查看现在卡中的信息
Reader ...........: canokeys.org OpenPGP PIV OATH 0
Application ID ...: C0987654321FEDCBA0987654321FEDCB
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: CanoKeys
Serial number ....: 0131313A
Name of cardholder: Zhang San
Language prefs ...: zh
Salutation .......: Mr.
URL of public key : https://www.hetong-re4per.com/HeTongRe4per.pub
Login data .......: ZhangSan
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=on Decrypt=off Auth=on
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
gpg/card> q # 退出卡信息编辑
接下来使用gpg --edit-key <主密钥指纹>开始转移密钥:
> gpg --edit-key 34567890ABCDEF12
gpg (GnuPG) 2.4.8; Copyright (C) 2025 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/34567890ABCDEF12
created: 2025-12-06 expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/01234567890ABCDE
created: 2025-12-06 expires: never usage: S
ssb cv25519/0E1234567890ABCD
created: 2025-12-06 expires: never usage: E
ssb ed25519/0AABCDEF09876543
created: 2025-12-06 expires: never usage: A
[ultimate] (1). Zhang San (xxxxx) <zhang.san@example.com>
gpg> key 1
sec ed25519/34567890ABCDEF12
created: 2025-12-06 expires: never usage: C
trust: ultimate validity: ultimate
ssb* ed25519/01234567890ABCDE # key1 的 ssb 后面有一个'*'表示被选中
created: 2025-12-06 expires: never usage: S
ssb cv25519/0E1234567890ABCD
created: 2025-12-06 expires: never usage: E
ssb ed25519/0AABCDEF09876543
created: 2025-12-06 expires: never usage: A
[ultimate] (1). Zhang San (xxxxx) <zhang.san@example.com>
gpg> keytocard # 使用 keytocard 转移到卡,会有 GUI 弹出先输入密钥的密码,再输入 Card 的管理员密码
Please select where to store the key:
(1) Signature key
(3) Authentication key
Your selection? 1 # 选择转的密钥功能为 Sign
Note: the local copy of the secret key will only be deleted with "save".
gpg> key 1 # 取消 key 1 的选择
...
gpg> key 2
gpg> keytocard
Please select where to store the key:
(2) Encryption key
Your selection? 2
gpg> key 2
gpg> key 3
gpg> keytocard
Please select where to store the key:
(3) Authentication key
Your selection? 3
gpg> save # 使用'save'退出并保存
接下来可以使用gpg --fingerprint --keyid-format long -K查看子密钥私钥状态,会发现三个 ssb 后面都有>,表示密钥已经存在了卡中,不在本地了:
> gpg --fingerprint --keyid-format long -K
[keyboxd]
---------
sec ed25519/34567890ABCDEF12 2025-12-06 [C]
Key fingerprint = ABCD EF12 3456 7890 ABCD EF12 3456 7890 ABCD EF12
uid [ultimate] Zhang San (xxxxx) <zhang.san@example.com>
ssb> ed25519/01234567890ABCDE 2025-12-06 [S]
ssb> cv25519/0E1234567890ABCD 2025-12-06 [E]
ssb> ed25519/0AABCDEF09876543 2025-12-06 [A]
再使用gpg --card-status查看卡的信息,可以发现我们的卡中已经有密钥了:
> gpg --card-status
Reader ...........: canokeys.org OpenPGP PIV OATH 0
Application ID ...: C0987654321FEDCBA0987654321FEDCB
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: CanoKeys
Serial number ....: 0131313A
Name of cardholder: Zhang San
Language prefs ...: zh
Salutation .......: Mr.
URL of public key : https://www.hetong-re4per.com/HeTongRe4per.pub
Login data .......: ZhangSan
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=on Decrypt=off Auth=on
Signature key ....: 0102 0304 0506 0708 0900 1111 3456 7890 ABCD EF12
created ....: 2025-12-06 19:28:54
Encryption key....: AABB CCDD EEFF 0011 2233 4455 0E12 3456 7890 ABCD
created ....: 2025-12-06 19:29:28
Authentication key: 00AA 11BB 33CC 44DD 55EE 66FF 0AAB CDEF 0987 6543
created ....: 2025-12-06 19:29:40
General key info..: sub ed25519/01234567890ABCDE 2025-12-06 Zhang San (xxxxx) <zhang.san@example.com>
sec ed25519/34567890ABCDEF12 created: 2025-12-06 expires: never
ssb> ed25519/01234567890ABCDE created: 2025-12-06 expires: never
card-no: F1D0 0131313A
ssb> cv25519/0E1234567890ABCD created: 2025-12-06 expires: never
card-no: F1D0 0131313A
ssb> ed25519/0AABCDEF09876543 created: 2025-12-06 expires: never
card-no: F1D0 0131313A
接下来使用gpg --delete-secret-keys <主密钥指纹>删除电脑主密钥,再使用gpg --import <主密钥公钥文件名>重新导入公钥:
gpg --delete-secret-keys 34567890ABCDEF12
gpg --import ZhangSan_0xABCDEF12_public.pub
日常使用密钥卡#
首先将密钥指向卡:
gpg --edit-card
gpg/card> fetch
如果你有多个硬件密钥,更换使用后会因为密钥指向的卡不存在而报错,可以使用gpg-connect-agent "scd serialno" "learn --force" /bye刷新卡状态
利用硬件密钥进行 git commit 签名#
使用git config --global user.signingkey <Sign密钥指纹>来指定 git 使用的签名指纹,如果是提交到 GitHub,可以在 GitHub SSH and GPG keys 中添加自己导出的公钥。添加成功后可以通过访问https://github.com/<GitHub账号>.gpg来查看你的公钥,也可以使用这个连接分发给其他人,例如我的 GitHub GPG 公钥。
在 WSL 中使用密钥卡#
首先在本地电脑上安装usbipd和gsudo:
winget install usbipd
winget install gerardog.gsudo
接下来在 WSL 中安装环境依赖:
sudo apt-get install linux-tools-virtual hwdata
sudo update-alternatives --install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20
回到 Windows 下,查看电脑上的 USB 设备,可以看到我们的硬件密钥的’BUSID’为2-2:
> usbipd list
Connected:
BUSID VID:PID DEVICE STATE
1-3 174f:2459 Integrated Camera, Camera DFU Device Not shared
1-4 048d:c101 USB 输入设备 Not shared
2-2 20a0:42d4 USB 输入设备, WebUSB, Microsoft Usbccid Smartcard Reader ... Shared
2-4 0bda:4852 Realtek Bluetooth Adapter Not shared
4-1 046d:c53f USB 输入设备 Not shared
4-3 320f:5055 USB 输入设备 Not shared
Persisted:
GUID DEVICE
然后将这个设备进行分享:
$ usbipd attach --wsl --busid 2-2
usbipd: info: Using WSL distribution 'Ubuntu-22.04' to attach; the device will be available in all WSL 2 distributions.
usbipd: info: Loading vhci_hcd module.
usbipd: info: Detected networking mode 'nat'.
usbipd: info: Using IP address 172.30.224.1 to reach the host.
回到 WSL,查看是否成功连接到,可以看见我们的硬件密钥「Clay Logic CanoKey Pigeon」:
$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 20a0:42d4 Clay Logic CanoKey Pigeon
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
在 WSL 中使用gpg --card-status试试:
$ gpg --card-status
Reader ...........: Canokeys Canokey [OpenPGP PIV OATH] (0131313A) 00 00
Application ID ...: C0987654321FEDCBA0987654321FEDCB
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: unknown
Serial number ....: 0131313A
Name of cardholder: Zhang San
Language prefs ...: zh
Salutation .......: Mr.
URL of public key : https://www.hetong-re4per.com/HeTongRe4per.pub
Login data .......: ZhangSan
Signature PIN ....: forced
Key attributes ...: ed25519 cv25519 ed25519
Max. PIN lengths .: 64 64 64
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: 0102 0304 0506 0708 0900 1111 3456 7890 ABCD EF12
created ....: 2025-12-06 19:28:54
Encryption key....: AABB CCDD EEFF 0011 2233 4455 0E12 3456 7890 ABCD
created ....: 2025-12-06 19:29:28
Authentication key: 00AA 11BB 33CC 44DD 55EE 66FF 0AAB CDEF 0987 6543
created ....: 2025-12-06 19:29:40
General key info..: [none]
可以看到确实连接到了,但是信息不全,需要我们导入公钥(关于公钥文件自己将自己的公钥用自己常用的方式放入 WSl 中即可):
gpg --import ZhangSan_0xABCDEF12_public.pub
再将密钥指向卡,同本小节开始日常使用部分一样:
gpg --edit-card
gpg/card> fetch
再使用gpg --card-status就可以看到我们的卡中的密钥信息了:
$ gpg --card-status
Reader ...........: Canokeys Canokey [OpenPGP PIV OATH] (0131313A) 00 00
Application ID ...: C0987654321FEDCBA0987654321FEDCB
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: unknown
Serial number ....: 0131313A
Name of cardholder: Zhang San
Language prefs ...: zh
Salutation .......: Mr.
URL of public key : https://www.hetong-re4per.com/HeTongRe4per.pub
Login data .......: ZhangSan
Signature PIN ....: forced
Key attributes ...: ed25519 cv25519 ed25519
Max. PIN lengths .: 64 64 64
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: 0102 0304 0506 0708 0900 1111 3456 7890 ABCD EF12
created ....: 2025-12-06 19:28:54
Encryption key....: AABB CCDD EEFF 0011 2233 4455 0E12 3456 7890 ABCD
created ....: 2025-12-06 19:29:28
Authentication key: 00AA 11BB 33CC 44DD 55EE 66FF 0AAB CDEF 0987 6543
created ....: 2025-12-06 19:29:40
General key info..:
sub ed25519/01234567890ABCDE 2025-12-06 Zhang San (xxxxx) <zhang.san@example.com>
sec ed25519/34567890ABCDEF12 created: 2025-12-06 expires: never
ssb> ed25519/01234567890ABCDE created: 2025-12-06 expires: never
card-no: F1D0 0131313A
ssb> cv25519/0E1234567890ABCD created: 2025-12-06 expires: never
card-no: F1D0 0131313A
ssb> ed25519/0AABCDEF09876543 created: 2025-12-06 expires: never
card-no: F1D0 0131313A
如果想回到 Windows 中使用密钥卡只需要在 PowerShell 中输入usbipd detach --busid 2-2即可。
利用 Auth 子密钥登录 SSH#
虽然 OpenSSH 支持 SSH with gpg agent,但 OpenSSH 8.3 版本后已经支持使用 FIDO2 来进行 SSH 登录了,故此我不推荐使用 SSH with gpg agent 来进行 SSH 登录,应当转为使用更现代,更便捷的 FIDO2 登录。如果你的硬件密钥真的只有 OpenPGP 的话可以在互联网上搜索 SSH with gpg agent 的食用方式。
本文作者: 褐瞳さん
本文链接: https://www.hetong-re4per.com/posts/record-of-using-openpgp-to-card/
版权声明: 本文文字在未特别注明下默认使用 CC BY-NC-SA 4.0 许可协议。




