PGP说明
时间1990年
作者菲利普·齐默曼
全称Pretty Good Privary
用途商业密码软件
支持平台Windows、Mac OS X、Linux
版本商用版、免费版
GnuPGGNU Privacy Guard,遵循OpenGPG规范编写的密码软件。

PGP设计目的是在连国家都不可信的情况下仍然能够使用,因此并不关心有没有可信的认证机构,而是采用了“由用户自己来决定信任谁”的设计。

简介

PGP是由菲利普·齐默曼于1990年左右编写的密码软件。

GnuPG(GNU Privacy Guard)是由GNU遵照OpenGPG(RFC4880)规范编写的自由软件。

OpenGPG

OpenGPG是对密文和数字签名格式进行定义的标准规格(RFC1991、RFC2440、RFC4880、RFC5581、RFC6637)。 密码学强度的平衡性见下图:

GNU Privacy Guard

GNU Privacy Guard是一款基于OpenGPG标准开发的密码学软件,支持加密、数字签名、密钥管理、S/MIME、ssh等多种功能。

GNU Privacy Guard说明
标准OpenGPG
用途加密、数字签名、密钥管理、S/MIME、ssh等
是否开源基于GNU GPL开源协议

PGP的功能

PGP具备现代密码软件所必须的几乎全部功能,主要有如下:

功能点说明
对称密码支持AES、IDEA、CAST、三重DES、Blowfish、Twofish、Camellia等算法。
公钥密码支持的公钥算法有RSA和ElGamal等。
数字签名支持的数字签名算法包括RSA、DSA、ECDSA(椭圆曲线DSA)、EdDSA(爱德华兹曲线DSA)等。
单向散列函数可以使用的单向散列算法包括SHA-1、SHA-224、SHA-256、SHA-384、SHA-512和RIPEMD-160等。
证书可以生成OpenGPG中规定格式的证书,以及与X.509规范兼容的证书。可以颁发公钥的作废证明,并使用CRL和OSCP对证书进行校验。
数据压缩支持数据的压缩和解压缩,压缩采用ZIP、ZLIB、BZIPZ等格式。
文本数据支持二进制数据和文本数据的相互转换。
大文件处理大文件拆分和小文件合并。
钥匙串管理用于管理自身生成的密钥对和外部获取的公钥。

生成密钥对

使用GnuPGv2生成密钥对的流程如下:

$ gpg2 --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)
  (14) Existing key from card
Your selection? 1 # 选择密钥类型(此时选择的加密算法和签名算法都是RSA)
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 2048 # 设置密钥的比特位数
Requested keysize is 2048 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) 1y # 设置密钥的有效期为1年
Key expires at 2024年07月04日 星期四 22时21分19秒 CST
Is this correct? (y/N) y # 确认有效期

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

Real name: Test
Name must be at least 5 characters long
Real name: TestDemo # 输入姓名
Email address: TestDemo@qq.com # 输入邮箱
Comment: TestDemoKeyPair # 输入备注
You selected this USER-ID:
    "TestDemo (TestDemoKeyPair) <TestDemo@qq.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O # 选择OK开始生成
# 会提示输入密钥保护口令界面
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.
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/blduan/.gnupg/trustdb.gpg: trustdb created # 创建信任网的数据库
gpg: key 646B0970D4B4C045 marked as ultimately trusted # 自身生成的密钥被设置为“绝对信任”
gpg: directory '/home/blduan/.gnupg/openpgp-revocs.d' created # 创建存放作废证书的目录
gpg: revocation certificate stored as '/home/blduan/.gnupg/openpgp-revocs.d/38D95500114918D89B33A278646B0970D4B4C045.rev' # 作废证书保存示例
public and secret key created and signed.

pub   rsa2048 2023-07-05 [SC] [expires: 2024-07-04] # 密钥对生成完毕
      38D95500114918D89B33A278646B0970D4B4C045
uid                      TestDemo (TestDemoKeyPair) <TestDemo@qq.com>
sub   rsa2048 2023-07-05 [E] [expires: 2024-07-04]

$ gpg2 --export --armor 646B0970D4B4C045 # 显示上面生成密钥对的公钥
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQENBGSlfKABCACeyttoiFlgzX4ZXAPJtrLC1yA7dWKg9s9EkKi2Susgv2nFOlHl
cadzXpPVW6Vx90uKRdfvLeDweY2UP6AF5DbXucJ8iiFuUfIe5agKm4PJI5+VBxWf
SGIY0Bjbgi8RWd6jg/ZtTbTiV7be9foi/7daIG0J2VA0Qqg+7oKx5h/fD6/ufygv
X9XDI6KqvAZ5N/NYJRhHrZCK6Ck+0IjlFhsrRmYHjPZwmBgwOypJNB0821EhrWSu
Kwe/rreBoca08fUMvlHxkm5rKmTjCrDT3+1+bcs3Fc0Zg2unCPt7eVPhwYe4hTxL
CNtjQkcgA4i+qObyX+RIqDC2CGP1H4Jy+WtLABEBAAG0LFRlc3REZW1vIChUZXN0
RGVtb0tleVBhaXIpIDxUZXN0RGVtb0BxcS5jb20+iQFUBBMBCgA+FiEEONlVABFJ
GNibM6J4ZGsJcNS0wEUFAmSlfKACGwMFCQHhM4AFCwkIBwIGFQoJCAsCBBYCAwEC
HgECF4AACgkQZGsJcNS0wEV6Egf/QqprnXIwjv7aEAYI5kP/y8y8z1116jk8Npg9
1D2Uaf/xGFD0DlmWe6SglBWK0iZiDig5+x4++nMIV1KbgF7a5MsTp5rwJk0pvWJx
B8H+IdRk2c2JoIPNHebVG2lALKuptqmnMsDcCUkM5ErepBCBZ6bZt9lKBKxa1m4N
STYI70SfybwWN7FWwg/jNtOpq3DLSF4cANLWPGY4AFy98PTsdxMpC3tRGPubuffk
nEyrqQuBth960liA1CdsvlgagevHW+/JZfUxfoNS6dukJIZa7vvn5/jAsGnWFQmF
amPkBCf51ao1AtAbuOXc0PW67ei5+RuVQhGjGBCGplIDfjhduLkBDQRkpXygAQgA
rJRcLIfVoiXqLmzpAT5QVhEY3lr1nk3GPUT9ZLly80np4IhXWn1O7J0i2wLKd+ew
xOG0bTpeqA3QWV7p50z6YH1LCrr2tKNMO1VxXdZD/7/lQiHbtrCXUaKnGPQP0Q2a
BhA8xrQ9C87+ehJx26vxi0Np+//pEB+QBGDqqOliLtC3GG85B1lUloShPQc99Vvt
xFHhmNVwWO9hVAgRjXts9JZw9kZMS7p+gHj70FZrvQfddRvOhJSdQ7jRxvMZFl5j
bNKnoJK3nDwT3JpIpUpt4944we31kPFhZKB5vK1CfNXlsVnumLjjr6ARepqb8IYd
oMr6X4HS2XztvMELoTDHTwARAQABiQE8BBgBCgAmFiEEONlVABFJGNibM6J4ZGsJ
cNS0wEUFAmSlfKACGwwFCQHhM4AACgkQZGsJcNS0wEVzIwf/Z0PPwAIytYRkUOzH
BwasRvKwmdgRgTjFYXyHgccdlbAs6YWmbsxzwiGsqYpA/SNY9NqWm67NIMfZremz
JvaSe1/o0eootaONkhy4J20WBwi4z8DB/uLFt85duNTzL81N4nTnVWKzhJVuaN6d
o35pC+ycXfL5rAUh1QKPJ3k2qk2a7aGWWke8JXRTwiTG6ZLzw6AXlnSyv1TKphLQ
TUg1Wr/Xf3byh/cxoZQ1Apd6AD0Ua6ClEDEG6AVO2zny51mR1STY64NJ4I8BJTgA
yQOIVQ4VMzpSTEwoIKPJHPKi4IOPl4G8Tb+hh6abkYwXzrvCJOmu1cQGx6vid9J2
Jf7Tfw==
=AQ/b
-----END PGP PUBLIC KEY BLOCK-----

GPG

加解密

PGP的加密过程和混合密码系统的结构基本一致,差异在于多了消息压缩以及二进制和文本的相互转换

加密

生成和加密会话密钥

  1. 用伪随机数生成器生成会话密钥。
  2. 用公钥密码加密会话密钥,这里指的是接收者的公钥。

压缩和加密消息

  1. 压缩消息。
  2. 使用步骤1中生成的会话密码作为对称密码对压缩的消息进行加密。
  3. 将步骤2中加密的会话密钥与步骤4中生成的加密消息拼接。
  4. 将步骤5中的数据转换为文本数据,即最后的报文数据。

解密

PGP的私钥都是保存在用户的钥匙串中。

为了防止钥匙串被盗,私钥都是以加密状态保存的,并在保存时使用了基于口令的密码(PBE)。

解密私钥

  1. 接收者输入解密的口令。
  2. 求口令的散列值,生成用于解密私钥的密钥。
  3. 将钥匙串中经过加密的私钥进行解密。

解密会话密钥

  1. 将报文数据(文本数据)转换为二进制数据。
  2. 将二进制数据分解为两部分:加密的会话密钥、经过压缩和加密的消息。
  3. 用步骤3中生成的公钥密码的私钥来解密会话密钥。

解密和解压缩消息

  1. 用步骤6生成的会话密钥来解密步骤5得到的经过压缩和加密的消息。
  2. 对步骤7得到的经过压缩的消息进行解压缩。
  3. 得到原始消息。

生成与验证数字签名

生成数字签名

解密私钥

  1. 发送者输入签名用的口令。
  2. 求口令散列值,生成用于解密私钥的密钥。
  3. 将钥匙串中经过加密的私钥进行解密。

生成数字签名

  1. 用单向散列函数计算消息的散列值。
  2. 使用步骤3得到的私钥对步骤4得到的散列值进行签名(相当于私钥加密)。
  3. 将步骤5生成的签名与消息进行组合。
  4. 将步骤6的结果进行压缩。
  5. 将步骤7的结果转换为文本数据。
  6. 步骤8的结果就是最终报文数据。

验证数字签名

恢复发送者发送的散列值

  1. 将报文数据转换为二进制数据。
  2. 对步骤1的数据进行解压缩。
  3. 将解压缩之后的数据分解为经过签名的散列值消息两部分。
  4. 将经过签名的散列值用发送者的公钥进行解密,还原出发送者发送的散列值。

对比散列值

  1. 使用单向散列函数计算步骤3得到的消息的散列值。
  2. 对比步骤4和步骤5得到的散列值。
  3. 步骤6对比结果相等,则数字签名验证成功,否则验证失败。
  4. 步骤3中得到的消息即为发送者发送的消息。

数字签名的使用

下面分别是在实际应用环境中签名与加密以及验证签名与解密的使用流程。

生成数字签名并对消息签名与加密

解密并验证数字签名

信任网

使用公钥密码的一个重大问题就是难以预防中间人攻击,不能确认公钥是否真正属于发送者,即公钥的合法性

为了解决这个问题,可以采用可信任证书机构对公钥施加数字签名,然后通过使用内置的该证书机构的根证书验证数字签名以确认证书合法性

PGP没有使用认证机构,而是采用了一种叫做信任网的做法。在这种方法中,PGP用户会互相对对方的公钥进行数字签名

具体来说,是如下规则:

  1. 当前用户将自己可以信任的人的公钥加入到公钥串,并使用自己的私钥进行签名。
  2. 如果接收到新公钥,根据公钥串中已添加的公钥对新的公钥进行验证签名
  3. 验证规则可以自行设置(和公钥串中的所有者信任级别有关)。
    1. 比如新公钥被公钥串中绝对信任级别的公钥进行签名并验证签名通过,则可确认新公钥可信;
    2. 或者新公钥被公钥串中有限信任级别的公钥进行签名并验证签名通过,但由于签名的公钥信任级别不够,因此新公钥不可信;
    3. 或者新公钥被公钥串中多个有限信任级别的公钥进行签名并验证通过,则也可以确认新公钥可信。

信任网类似于圈子,只有得到圈子中可以信任的人的推荐,新人才能够加入圈子。

所有者信任级别

在PGP中,用户可以设置对每个公钥所有者的信任级别,即PGP的用户可以自行设置对谁进行何种程度的信任

术语信任级别
Ultimately trusted绝对信任(是持有私钥的本人)
Fully trusted完全信任
Marginally trusted有限信任
Nerver trust this key不信任
Not enough information未知密钥
No owner trust assigned未设置

公钥合法性与所有者信任级别

“公钥是否合法”与“所有者是否可信”是不同的,尽管公钥合法,但其所有者也可以是不可信的。

因为不能确认公钥所有者在数字签名上的判断能力或者对私钥的管理能力。比如虽然可以确定其公钥的所有者,但是该公钥所有者不靠谱,不能作为担保人,因此他签名的公钥也是不可信的。

所有者信任级别是因人而异的。

PGP的用户可以自行设置对谁进行何种程度的信任,PGP就是根据信任数据库中的设置来判断所得到的公钥是否属于本人的。

PGP当初的设计目的是在连国家都不可信的情况下仍然能够使用,因此并不关心有没有可信的认证机构,而是采用了“由用户自己来决定信任谁”的设计。