上篇文章 加密软件 GPG 上手教程 介绍了 GPG 的基础使用,这篇文章作为上一篇的延续,分享 GPG 最佳实践。
创建职责分离主密钥与子秘钥
在 GPG 的架构中,
- 主密钥必须具有[C] 功能,可兼备[S]、[E]、[A]功能中的一项或多项,
- 子秘钥可具有[S]、[E]、[A]功能中的一项或多项。
为什么要创建职责分离的主密钥与子秘钥呢?
首先子秘钥是一个单独的秘钥对,与主密钥只是从属关系,在功能上是完全独立的,而且子秘钥可以独立于主密钥被吊销。
其次,主密钥非常重要。如果主密钥被盗,别人一旦获得了主密钥的控制权,就能用你的名义做任何事情,比如签署文件,解密信息等。而且吊销主密钥会带来巨大的成本损失——你需要重新建立信任。由于信任网的每个连接都是对主密钥和用户 ID 之间绑定的认可,与子秘钥无关(子秘钥的创建和吊销不会影响主密钥之间的信任关系)。所以,如果在主密钥安全的情况下子秘钥被盗,你只需吊销被盗的子秘钥,并签发新的子秘钥即可。
创建主密钥
gpg --expert --full-gen-key |
gpg (GnuPG) 2.2.27; 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 (default) |
(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 and ECC |
(10) ECC (sign only) |
(11) ECC (set your own capabilities) |
(13) Existing key |
(14) Existing key from card |
Your selection? 8 |
Possible actions for a RSA key: Sign Certify Encrypt Authenticate |
Current allowed actions: Sign Certify Encrypt |
(S) Toggle the sign capability |
(E) Toggle the encrypt capability |
(A) Toggle the authenticate capability |
(Q) Finished |
Your selection? s |
Possible actions for a RSA key: Sign Certify Encrypt Authenticate |
Current allowed actions: Certify Encrypt |
(S) Toggle the sign capability |
(E) Toggle the encrypt capability |
(A) Toggle the authenticate capability |
(Q) Finished |
Your selection? e |
Possible actions for a RSA key: Sign Certify Encrypt Authenticate |
Current allowed actions: Certify |
(S) Toggle the sign capability |
(E) Toggle the encrypt capability |
(A) Toggle the authenticate capability |
(Q) Finished |
Your selection? q |
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) 3y |
Key expires at Sun 23 Mar 2025 04:51:32 GMT |
Is this correct? (y/N) y |
GnuPG needs to construct a user ID to identify your key. |
Real name: alice |
Email address: alice@example.com |
Comment: |
You selected this USER-ID: |
"alice <alice@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: /home/alice/.gnupg/trustdb.gpg: trustdb created |
gpg: key A39421B65EF4D2D7 marked as ultimately trusted |
gpg: directory '/home/alice/.gnupg/openpgp-revocs.d' created |
gpg: revocation certificate stored as '/home/alice/.gnupg/openpgp-revocs.d/C105EE41AB5FDFAB2D00F2FFA39421B65EF4D2D7.rev' |
public and secret key created and signed. |
pub rsa4096 2022-03-24 [C] [expires: 2025-03-23] |
C105EE41AB5FDFAB2D00F2FFA39421B65EF4D2D7 |
uid alice <alice@example.com> |
创建加密功能的子秘钥
gpg --expert --edit-key alice@example.com |
gpg (GnuPG) 2.2.27; 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. |
Secret key is available. |
sec rsa4096/A39421B65EF4D2D7 |
created: 2022-03-24 expires: 2025-03-23 usage: C |
trust: ultimate validity: ultimate |
[ultimate] (1). alice <alice@example.com> |
gpg> addkey |
Please select what kind of key you want: |
(3) DSA (sign only) |
(4) RSA (sign only) |
(5) Elgamal (encrypt only) |
(6) RSA (encrypt only) |
(7) DSA (set your own capabilities) |
(8) RSA (set your own capabilities) |
(10) ECC (sign only) |
(11) ECC (set your own capabilities) |
(12) ECC (encrypt only) |
(13) Existing key |
(14) Existing key from card |
Your selection? 6 |
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) 3y |
Key expires at Sun 23 Mar 2025 04:59:04 GMT |
Is this correct? (y/N) y |
Really create? (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 rsa4096/A39421B65EF4D2D7 |
created: 2022-03-24 expires: 2025-03-23 usage: C |
trust: ultimate validity: ultimate |
ssb rsa4096/18832C062E4EBE77 |
created: 2022-03-24 expires: 2025-03-23 usage: E |
[ultimate] (1). alice <alice@example.com> |
gpg> save |
秘钥创建完成后如下:
gpg --edit-key alice@example.com |
gpg (GnuPG) 2.2.27; 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. |
Secret key is available. |
sec rsa4096/A39421B65EF4D2D7 |
created: 2022-03-24 expires: 2025-03-23 usage: C |
trust: ultimate validity: ultimate |
ssb rsa4096/18832C062E4EBE77 |
created: 2022-03-24 expires: 2025-03-23 usage: E |
ssb rsa4096/EFE05191993439D6 |
created: 2022-03-24 expires: 2025-03-23 usage: S |
ssb rsa4096/5B4D08C955707D10 |
created: 2022-03-24 expires: 2025-03-23 usage: A |
[ultimate] (1). alice <alice@example.com> |
使用主密钥的场景
主密钥只具有[C]功能,只在以下情形时使用主密钥:
- 签署其他人密钥或撤销现有签名;
- 添加新身份信息或将现有 UID 标记为主 UID;
- 创建新子秘钥;
- 撤销现有 UID 或子密钥;
- 更改 UID 的首选项(例如,使用 setpref);
- 更改主密钥或其任何子秘钥的过期日期;
- 撤销或生成完整密钥的撤销证书。
备份方案
方案一:单独导出备份文件
# 备份步骤 |
# step 1: 导出秘钥信息,其中包括所有公钥,私钥,信任网数据库文件,进行备份 |
gpg --export > public-keys.gpg |
gpg --export-secret-keys > private-keys.gpg |
gpg --export-ownertrust > ownertrust.asc |
# step 2: 导出秘钥吊销凭证,建议单独备份 |
gpg --armor --gen-revoke [primary key ID] > revocation.asc |
# 恢复秘钥 |
# step 1: 导出公钥,私钥和信任网数据库 |
gpg --import pgp-public-keys.asc |
gpg --import pgp-private-keys.asc |
gpg --import-ownertrust pgp-ownertrust.asc |
# 如果秘钥泄露,需要吊销秘钥 |
gpg --import pgp-revocation.asc |
方案二:全文件夹备份,加密保存
# 压缩目录,备份文件 |
tar -zcvf gnupg.tar.gz ~/.gnupg/* |
# 恢复秘钥,解压文件 |
tar -zxvf gnupg.tar.gz |
个人喜欢方案二,只要保证备份和解压时的权限是安全的,后者更方便。特殊场合使用时插上 U 盘直接在 U 盘中对秘钥进行操作,由于不涉及到硬盘读写,自然不会在硬盘中留下痕迹。
主密钥离线使用
主密钥和子秘钥职责分离后,用到主密钥的场合非常少。需要主密钥执行某些操作时,插上 U 盘,保证环境权限安全的情况下,解压 gnupg.tar.gz
,恢复秘钥即可。
使用时可通过设置环境变量的方式
export GNUPGHOME=/media/yourdrive/path/to/.gnupg |
gpg -k |
或者使用 --homedir
参数。
gpg --homedir=/media/yourdrive/path/to/.gnupg -k |
而日常使用中,涉及到加密、签名和身份认证,使用子秘钥的场合会更多一些。这里的要点是让主密钥的私钥(secret primary key)离线,同时重设新密码来保护子秘钥。使用这种方式,就算新密码被泄露,主私钥(secret primary key)依然保持安全——备份的秘钥仍在旧密码的保护中且主私钥文件没有泄露。
# step 1:导出子私钥,公钥和信任信息 |
gpg --export-secret-subkeys > private-subkeys.gpg # 注意:是 --export-secret-subkeys 而不是 --export-secret-keys |
gpg --export > public-keys.gpg |
gpg --export-ownertrust > ownertrust.asc |
# step 2: 重新恢复秘钥,目的是让 sec(secret primary key)离线 |
gpg --import private-subkeys.gpg |
gpg --import public-keys.gpg |
gpg --import-ownertrust ownertrust.asc |
# step 3: 检查是否离线,以 sec 后面带有#为准 |
gpg -K |
/home/alice/.gnupg/pubring.kbx |
--------------------------- |
sec# rsa3072 2022-03-25 [SC] |
C105EE41AB5FDFAB2D00F2FFA39421B65EF4D2D7 |
uid [ultimate] alice <alice@example.com> |
ssb rsa3072 2022-03-25 [E] |
# step 4: 修改密码,更换为新的密码 |
gpg --change-passphrase C105EE41AB5FDFAB2D00F2FFA39421B65EF4D2D7 |
保持更新公钥
定期更新公钥,及时同步对方公钥的过期、撤销信息,避免在对方已撤销公钥的情况下发送加密信息,务必确认公钥的有效性。