主页 > 原创 | 整理 > PGP密钥创建及GPG使用

PGP密钥创建及GPG使用

PGP (Pretty Good Privacy) 是一种非对称加密机制,有一个公钥和私钥对,其中公钥公开存储在公网上,私钥由个人安全的保存在本地。

一个简单的使用场景是 读者使用我的公钥 F1C68AB4 加密一个文件,如 abc.txt -> abc.txt.gpg 并发送给我,我收到这个 abc.txt.gpg 文件后,通过我的本地私钥来解密这个文件到 abc.txt 并读取内容。

如果没有私钥,是不可能解读到被加密的内容的,所以可以确保消息内容不被中间人监听、泄露。

系统环境

Archlinux, gpg (GnuPG) 2.1.19

配置

修改 ~/.gnupg/gpg.conf 文件,添加 keyserver 内容如下

keyserver hkp://keys.gnupg.net

修改 ~/.gnupg/gpg-agent.conf 文件,添加如下内容

allow-loopback-pinentry
pinentry-program /usr/bin/pinentry-curses

修改 ~/.gnupg/dirmngr.conf 文件,添加如下内容

standard-resolver

杀死所有的 gpg-agentdirmngr 进程

killall gpg-agent
killall dirmngr

1. 获取已被发布的公钥

gpg --recv-keys F1C68AB4

返回内容如下

gpg: key 09295FD1F1C68AB4: public key "tianyu <xdtianyu*gmail.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1

查看已经导入的公钥

gpg --list-keys

返回内容如下

/root/.gnupg/pubring.kbx
------------------------
pub   rsa2048 2015-12-14 [SC]
      EAB335E167A6739677E1879609295FD1F1C68AB4
uid           [ unknown] tianyu <xdtianyu*gmail.com>
uid           [ unknown] tianyu <admin*xdty.org>
sub   rsa2048 2015-12-14 [E]

其中 EAB335E167A6739677E1879609295FD1F1C68AB4 是长 ID, 可以通过 --keyid-format (SHORT/LONG) 参数来查看短一点的 ID,方便与其他人交换。

gpg --list-keys --keyid-format SHORT

返回内容如下

/root/.gnupg/pubring.kbx
------------------------
pub   rsa2048/F1C68AB4 2015-12-14 [SC]
      EAB335E167A6739677E1879609295FD1F1C68AB4
uid         [ unknown] tianyu <xdtianyu*gmail.com>
uid         [ unknown] tianyu <admin*xdty.org>
sub   rsa2048/F046E25B 2015-12-14 [E]

其中的 rsa2048/F1C68AB4 就是最开始导入的 ID。

2. 创建 PGP 密钥对

参考 Generating a new GPG key

注意,如果是 ssh 远程登陆,建议使用 screen 操作,避免 pinentry 出现问题。

gpg --full-generate-key

交互流程如下

gpg (GnuPG) 2.1.19; Copyright (C) 2017 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)
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 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)
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: myname
Email address: myname@mydomain.com
Comment: test pgp
You selected this USER-ID:
    "myname (test pgp) <myname@mydomain.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.

            ┌──────────────────────────────────────────────────────┐
            │ Please enter the passphrase to                       │
            │ protect your new key                                 │
            │                                                      │
            │ Passphrase: ********________________________________ │
            │                                                      │
            │       <OK>                              <Cancel>     │
            └──────────────────────────────────────────────────────┘

            ┌──────────────────────────────────────────────────────┐
            │ Please re-enter this passphrase                      │
            │                                                      │
            │ Passphrase: ********________________________________ │
            │                                                      │
            │       <OK>                              <Cancel>     │
            └──────────────────────────────────────────────────────┘

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: key 66078F7054E76435 marked as ultimately trusted
gpg: directory '/root/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/767FA3A9F943376B4AA469B566078F7054E76435.rev'
public and secret key created and signed.

pub   rsa4096 2017-04-13 [SC]
      767FA3A9F943376B4AA469B566078F7054E76435
      767FA3A9F943376B4AA469B566078F7054E76435
uid                      myname (test pgp) <myname@mydomain.com>
sub   rsa4096 2017-04-13 [E]

再次通过 gpg --list-keys --keyid-format SHORT 命令查看已经导入的公钥

gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
/root/.gnupg/pubring.kbx
------------------------
pub   rsa2048/F1C68AB4 2015-12-14 [SC]
      EAB335E167A6739677E1879609295FD1F1C68AB4
uid         [ unknown] tianyu <xdtianyu*gmail.com>
uid         [ unknown] tianyu <admi*xdty.org>
sub   rsa2048/F046E25B 2015-12-14 [E]

pub   rsa4096/54E76435 2017-04-13 [SC]
      767FA3A9F943376B4AA469B566078F7054E76435
uid         [ultimate] myname (test pgp) <myname*mydomain.com>
sub   rsa4096/B8F96DC9 2017-04-13 [E]

可以看到已经生成 ID 为 54E76435 的公钥。

其中的 ultimate 表示完全信任,而 unknown 则表示不能信任是否真的是这个邮箱所有者的公钥,因为 PGP 没有邮箱验证机制,所以需要和对方确认ID。

自己新建的公钥自然是可信的,所以默认是 ultimate,而导入的公钥不能验证对方填写的邮箱地址,所以是 unknown

可以通过 gpg --edit-key F1C68AB4 来更新信任状态,这样在用这个公钥加密的时候就不会弹出信任提示了。

gpg (GnuPG) 2.1.19; Copyright (C) 2017 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.


pub  rsa2048/09295FD1F1C68AB4
     created: 2015-12-14  expires: never       usage: SC  
     trust: unknown       validity: unknown
sub  rsa2048/E1F7D3ADF046E25B
     created: 2015-12-14  expires: never       usage: E  
[ unknown] (1). tianyu <xdtianyu*gmail.com>
[ unknown] (2)  tianyu <admin*xdty.org>

gpg> trust
pub  rsa2048/09295FD1F1C68AB4
     created: 2015-12-14  expires: never       usage: SC  
     trust: unknown       validity: unknown
sub  rsa2048/E1F7D3ADF046E25B
     created: 2015-12-14  expires: never       usage: E  
[ unknown] (1). tianyu <xdtianyu*gmail.com>
[ unknown] (2)  tianyu <admin*xdty.org>

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

pub  rsa2048/09295FD1F1C68AB4
     created: 2015-12-14  expires: never       usage: SC  
     trust: ultimate      validity: unknown
sub  rsa2048/E1F7D3ADF046E25B
     created: 2015-12-14  expires: never       usage: E  
[ unknown] (1). tianyu <xdtianyu*gmail.com>
[ unknown] (2)  tianyu <admin*xdty.org>
Please note that the shown key validity is not necessarily correct
unless you restart the program.

gpg> save
Key not changed so no update needed.

再次通过 gpg --list-keys --keyid-format SHORT 命令查看已经导入的公钥,可以看到都变成 ultimate 状态。

/root/.gnupg/pubring.kbx
------------------------
pub   rsa2048/F1C68AB4 2015-12-14 [SC]
      EAB335E167A6739677E1879609295FD1F1C68AB4
uid         [ultimate] tianyu <xdtianyu@gmail.com>
uid         [ultimate] tianyu <admin@xdty.org>
sub   rsa2048/F046E25B 2015-12-14 [E]

pub   rsa4096/54E76435 2017-04-13 [SC]
      767FA3A9F943376B4AA469B566078F7054E76435
uid         [ultimate] myname (test pgp) <myname@mydomain.com>
sub   rsa4096/B8F96DC9 2017-04-13 [E]

使用 gpg --list-secret-keys --keyid-format SHORT 查看生成的私钥信息

/root/.gnupg/pubring.kbx
------------------------
sec   rsa4096/54E76435 2017-04-13 [SC]
      767FA3A9F943376B4AA469B566078F7054E76435
uid         [ultimate] myname (test pgp) <myname@mydomain.com>
ssb   rsa4096/B8F96DC9 2017-04-13 [E]

3. 发布公钥

上一步已经生成了 ID 为 54E76435 的 pgp 密钥对,通过如下命令发布公钥到服务器

gpg --send-key 54E76435

返回内容如下

gpg: sending key 66078F7054E76435 to hkp://keys.gnupg.net

等待几分钟后,在另一个电脑上运行导入命令

gpg --ignore-time-conflict --recv-keys 54E76435

返回如下

gpg: requesting key 54E76435 from hkp server keys.gnupg.net
gpg: key 54E76435 was created 26761 seconds in the future (time warp or clock problem)
gpg: key 54E76435 was created 26761 seconds in the future (time warp or clock problem)
gpg: key 54E76435 was created 26761 seconds in the future (time warp or clock problem)
gpg: key 54E76435 was created 26761 seconds in the future (time warp or clock problem)
gpg: key 54E76435 was created 26761 seconds in the future (time warp or clock problem)
gpg: key 54E76435 was created 26761 seconds in the future (time warp or clock problem)
gpg: key 54E76435: public key "myname (test pgp) <myname@mydomain.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)

出现的时间错误是因为主机时间和服务器的时间时区不一至导致的。

gpg --list-keys
/home/ty/.gnupg/pubring.gpg
---------------------------

gpg: key 54E76435 was created 26648 seconds in the future (time warp or clock problem)
gpg: key 54E76435 was created 26648 seconds in the future (time warp or clock problem)
pub   4096R/54E76435 2017-04-13
uid                  myname (test pgp) <myname@mydomain.com>
sub   4096R/B8F96DC9 2017-04-13

可以看到成功导入了上一步生成的公钥。

4. 使用公钥加密文件

导入公钥后,就可以通过公钥来加密文件了,使用如下命令测试

echo abc > aaa.txt
gpg -r 54E76435 -e aaa.txt

返回结果如下

gpg: B8F96DC9: There is no assurance this key belongs to the named user

pub  4096R/B8F96DC9 2017-04-13 myname (test pgp) <myname@mydomain.com>
 Primary key fingerprint: 767F A3A9 F943 376B 4AA4  69B5 6607 8F70 54E7 6435
      Subkey fingerprint: 600A 7788 9913 7A6A 7351  C89B C276 C3D1 B8F9 6DC9

It is NOT certain that the key belongs to the person named
in the user ID.  If you *really* know what you are doing,
you may answer the next question with yes.

Use this key anyway? (y/N) y

注意这个提示可以通过上文提到的 gpg --edit-key 54E76435 来更新信任状态。

发送生成的 aaa.txt.gpg 文件到含有 54E76435 私钥的机器上。

注意,如果需要生成文本格式的加密内容,可以使用 -a, --armor 参数

gpg -r 54E76435 -e -a aaa.txt

之后将生成 aaa.txt.asc 文本文件,内容示例如下

-----BEGIN PGP MESSAGE-----
Version: GnuPG v1

hQEMA+H3063wRuJbAQf+ISBZcZWP7Pxm/r4NSAK/M+ArhUw7PY9Cksl8H06BmgnD
...
mEPWYJw4oCmzO4HWENvhSJOOHbg+OzDrbq4AhdfU+gkcBbLiD5B8S76pEmAYBchF
85a2
=DA/w
-----END PGP MESSAGE-----

5. 使用私钥解密文件

通过如下命令解密上一步生成的 aaa.txt.gpg 文件

gpg -d aaa.txt.gpg

第一次使用解密命令时会提示输入私钥密码,之后一段时间再解密将不再需要输入密码。

       ┌────────────────────────────────────────────────────────────────┐
       │ Please enter the passphrase to unlock the OpenPGP secret key:  │
       │ "myname (test pgp) <myname@mydomain.com>"                      │
       │ 4096-bit RSA key, ID C276C3D1B8F96DC9,                         │
       │ created 2017-04-13 (main key ID 66078F7054E76435).             │
       │                                                                │
       │                                                                │
       │ Passphrase: ********__________________________________________ │
       │                                                                │
       │         <OK>                                    <Cancel>       │
       └────────────────────────────────────────────────────────────────┘

gpg: encrypted with 4096-bit RSA key, ID C276C3D1B8F96DC9, created 2017-04-13
      "myname (test pgp) <myname@mydomain.com>"
abc

6. 通过文本密码加密文件

gpg 可以通过文本密码来加密文件,注意这种加密方式就是普通形式的密码加密,不需要密钥对

gpg -c aaa.txt
gpg -c aaa.txt
            ┌──────────────────────────────────────────────────────┐
            │ Enter passphrase                                     │
            │                                                      │
            │                                                      │
            │ Passphrase: *******_________________________________ │
            │                                                      │
            │       <OK>                              <Cancel>     │
            └──────────────────────────────────────────────────────┘

            ┌──────────────────────────────────────────────────────┐
            │ Please re-enter this passphrase                      │
            │                                                      │
            │ Passphrase: *******_________________________________ │
            │                                                      │
            │       <OK>                              <Cancel>     │
            └──────────────────────────────────────────────────────┘

可以将生成的 aaa.txt.gpg 文件发送给其他人,并直接通过密码解密。

gpg -d aaa.txt.gpg

7. 添加新的用户 ID 到密钥对并发布更新公钥

可以通过 gpg --edit-key 54E76435 增加新的邮箱地址到密钥对

gpg (GnuPG) 2.1.19; Copyright (C) 2017 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/66078F7054E76435
     created: 2017-04-13  expires: never       usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa4096/C276C3D1B8F96DC9
     created: 2017-04-13  expires: never       usage: E  
[ultimate] (1). myname (test pgp) <myname@mydomain.com>

gpg> adduid
Real name: myname2
Email address: myname2@mydomain2.com
Comment: test pgp 2
You selected this USER-ID:
    "myname2 (test pgp 2) <myname2@mydomain2.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o

sec  rsa4096/66078F7054E76435
     created: 2017-04-13  expires: never       usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa4096/C276C3D1B8F96DC9
     created: 2017-04-13  expires: never       usage: E  
[ultimate] (1)  myname (test pgp) <myname@mydomain.com>
[ unknown] (2). myname2 (test pgp 2) <myname2@mydomain2.com>

gpg> trust
sec  rsa4096/66078F7054E76435
     created: 2017-04-13  expires: never       usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa4096/C276C3D1B8F96DC9
     created: 2017-04-13  expires: never       usage: E  
[ultimate] (1)  myname (test pgp) <myname@mydomain.com>
[ unknown] (2). myname2 (test pgp 2) <myname2@mydomain2.com>

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

sec  rsa4096/66078F7054E76435
     created: 2017-04-13  expires: never       usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa4096/C276C3D1B8F96DC9
     created: 2017-04-13  expires: never       usage: E  
[ultimate] (1)  myname (test pgp) <myname@mydomain.com>
[ unknown] (2). myname2 (test pgp 2) <myname2@mydomain2.com>

gpg> save

再次通过 gpg --list-keys 查看当前的公钥,可以看到新的 UID 已经被加入到密钥对中。

gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   2  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2u
/root/.gnupg/pubring.kbx
------------------------
pub   rsa4096 2017-04-13 [SC]
      767FA3A9F943376B4AA469B566078F7054E76435
uid           [ultimate] myname2 (test pgp 2) <myname2@mydomain2.com>
uid           [ultimate] myname (test pgp) <myname@mydomain.com>
sub   rsa4096 2017-04-13 [E]

通过 gpg --send-key 54E76435 命令更新公钥到服务器。

gpg: sending key 66078F7054E76435 to hkp://keys.gnupg.net

8. 导出和导入公钥

如果不想通过公网服务器交换公钥,也可以导出公钥文件,交换公钥文件后再导入对方计算机

通过 gpg --list-keys 命令查看当前的公钥,显示如下

/root/.gnupg/pubring.kbx
------------------------

pub   rsa4096 2017-04-13 [SC]
      767FA3A9F943376B4AA469B566078F7054E76435
uid           [ultimate] myname2 (test pgp 2) <myname2@mydomain2.com>
uid           [ultimate] myname (test pgp) <myname@mydomain.com>
sub   rsa4096 2017-04-13 [E]

再通过 gpg --export -a 767FA3A9F943376B4AA469B566078F7054E76435gpg --export -a myname 命令导出公钥文本

-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBFjvsHwBEACxl35XbDv2GhrLg0wW9u2oYxf2AOL/cw22UCiKTjnTYlOj4J0j
t5zMSdsE33FfqI5qmgZBrxhWoIPSb+V0ltIyXHDu9OeM0W4Tj7iNEW4WU+Gdpx9y
......
1MNNkK4EIbOWj29pT7rB4JpsZsjOyhGRL9U5kSNHJxK93yfzvFgWvoxEaQw0kQij
Fjo/bOsGrWaRw951UGAif6i5haHmsvHdPD0R/M4wAb29XWricszbMYCju0ry1pyy
yfY3ETZ3Yo+3BhC5Pxlq3aQM
=KR0j
-----END PGP PUBLIC KEY BLOCK-----

发送这个公钥文本文件给对方后,如保存为 myname.asc 文件,对方可以通过 gpg --import myname.asc 命令导入公钥。返回内容如下

gpg: key 66078F7054E76435: "myname2 (test pgp 2) <myname2@mydomain2.com>" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1

9. 导出和备份私钥

私钥一旦丢失,被加密的文件将不能解密,所以将私钥备份在安全的地方很重要。可以通过

gpg --export-secret-keys -a 767FA3A9F943376B4AA469B566078F7054E76435 > myname.secret.asc

命令来保存私钥到本地文件。输入密码后会在本地生成 myname.secret.asc 文件,可以备份到 Dropbox 等服务。

之后如果私钥丢失,可以通过 gpg --import myname.secret.asc 命令导入私钥文件。

使用密钥解密文件会要求输入密码,是私钥泄漏后的一个保障,因为私钥太重要,私钥和私钥密码一定不能泄漏。

Tags: gpg gunpg linux pgp

评论:5

  1. 千千w 回复
    2017 年 8 月 15 日 于 上午 10:48

    cool!天宇酱

  2. thornbird 回复
    2018 年 1 月 19 日 于 上午 8:18

    你的博客好久没有更新了

  3. Aw 回复
    2018 年 3 月 14 日 于 下午 3:15

    嗷呜,天宇桑

  4. kubaoya 回复
    2018 年 11 月 20 日 于 下午 4:51

    哇,公钥私钥秘钥实际应用起来好难啊

  5. 心灵博客 回复
    2019 年 6 月 18 日 于 下午 3:18

    天宇桑再也不更新了吗?

发表评论

邮箱地址不会被公开。 必填项已用*标注