上篇文章 加密软件 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 |
保持更新公钥
定期更新公钥,及时同步对方公钥的过期、撤销信息,避免在对方已撤销公钥的情况下发送加密信息,务必确认公钥的有效性。