公钥基础设施和密码学中的私钥的角色
了解如何验证某人所声称的身份。在上一篇文章中，我们概述了密码学并讨论了密码学的核心概念： 保密性 confidentiality （让数据保密）、 完整性 integrity （防止数据被篡改）和 身份认证 authentication （确认数据源的 身份 identity ）。由于要在存在各种身份混乱的现实世界中完成身份认证，人们逐渐建立起一个复杂的 技术生态体系 technological ecosystem ，用于证明某人就是其声称的那个人。在本文中，我们将大致介绍这些体系是如何工作的。快速回顾公钥密码学及数字签名互联网世界中的身份认证依赖于公钥密码学，其中密钥分为两部分：拥有者需要保密的私钥和可以对外公开的公钥。经过公钥加密过的数据，只能用对应的私钥解密。举个例子，对于希望与记者建立联系的举报人来说，这个特性非常有用。但就本文介绍的内容而言，私钥更重要的用途是与一个消息一起创建一个 数字签名 digital signature ，用于提供完整性和身份认证。在实际应用中，我们签名的并不是真实消息，而是经过 密码学哈希函数 cryptographic hash function 处理过的消息 摘要 digest 。要发送一个包含源代码的压缩文件，发送者会对该压缩文件的 256 比特长度的 SHA-256 摘要进行签名，而不是文件本身进行签名，然后用明文发送该压缩包（和签名）。接收者会独立计算收到文件的 SHA-256 摘要，然后结合该摘要、收到的签名及发送者的公钥，使用签名验证算法进行验证。验证过程取决于加密算法，加密算法不同，验证过程也相应不同；而且，很微妙的是签名验证漏洞依然层出不穷。如果签名验证通过，说明文件在传输过程中没有被篡改而且来自于发送者，这是因为只有发送者拥有创建签名所需的私钥。方案中缺失的环节上述方案中缺失了一个重要的环节：我们从哪里获得发送者的公钥？发送者可以将公钥与消息一起发送，但除了发送者的自我宣称，我们无法核验其身份。假设你是一名银行柜员，一名顾客走过来向你说，“你好，我是 Jane Doe，我要取一笔钱”。当你要求其证明身份时，她指着衬衫上贴着的姓名标签说道，“看，Jane Doe！”。如果我是这个柜员，我会礼貌的拒绝她的请求。如果你认识发送者，你们可以私下见面并彼此交换公钥。如果你并不认识发送者，你们可以私下见面，检查对方的证件，确认真实性后接受对方的公钥。为提高流程效率，你可以举办聚会并邀请一堆人，检查他们的证件，然后接受他们的公钥。此外，如果你认识并信任 Jane Doe（尽管她在银行的表现比较反常），Jane 可以参加聚会，收集大家的公钥然后交给你。事实上，Jane 可以使用她自己的私钥对这些公钥（及对应的身份信息）进行签名，进而你可以从一个线上密钥库)获取公钥（及对应的身份信息）并信任已被 Jane 签名的那部分。如果一个人的公钥被很多你信任的人（即使你并不认识他们）签名，你也可能选择信任这个人。按照这种方式，你可以建立一个 信任网络 Web of Trust 。但事情也变得更加复杂：我们需要建立一种标准的编码机制，可以将公钥和其对应的身份信息编码成一个 数字捆绑 digital bundle ，以便我们进一步进行签名。更准确的说，这类数字捆绑被称为 证书 cerificate 。我们还需要可以创建、使用和管理这些证书的工具链。满足诸如此类的各种需求的方案构成了 公钥基础设施 public key infrastructure （PKI）。比信任网络更进一步你可以用人际关系网类比信任网络。如果人们之间广泛互信，可以很容易找到（两个人之间的）一条 短信任链 short path of trust ：就像一个社交圈。基于 GPG 加密的邮件依赖于信任网络，（理论上）只适用于与少量朋友、家庭或同事进行联系的情形。（LCTT 译注：作者提到的“短信任链”应该是暗示“六度空间理论”，即任意两个陌生人之间所间隔的人一般不会超过 6 个。对 GPG 的唱衰，一方面是因为密钥管理的复杂性没有改善，另一方面 Yahoo 和 Google 都提出了更便利的端到端加密方案。）在实际应用中，信任网络有一些“ 硬伤 significant problems ”，主要是在可扩展性方面。当网络规模逐渐增大或者人们之间的连接较少时，信任网络就会慢慢失效。如果信任链逐渐变长，信任链中某人有意或无意误签证书的几率也会逐渐增大。如果信任链不存在，你不得不自己创建一条信任链，与其它组织建立联系，验证它们的密钥以符合你的要求。考虑下面的场景，你和你的朋友要访问一个从未使用过的在线商店。你首先需要核验网站所用的公钥属于其对应的公司而不是伪造者，进而建立安全通信信道，最后完成下订单操作。核验公钥的方法包括去实体店、打电话等，都比较麻烦。这样会导致在线购物变得不那么便利（或者说不那么安全，毕竟很多人会图省事，不去核验密钥）。如果世界上有那么几个格外值得信任的人，他们专门负责核验和签发网站证书，情况会怎样呢？你可以只信任他们，那么浏览互联网也会变得更加容易。整体来看，这就是当今互联网的工作方式。那些“格外值得信任的人”就是被称为 证书颁发机构 cerificate authoritie （CA）的公司。当网站希望获得公钥签名时，只需向 CA 提交 证书签名请求 certificate signing request （CSR）。CSR 类似于包括公钥和身份信息（在本例中，即服务器的主机名）的 存根 stub 证书，但 CA 并不会直接对 CSR 本身进行签名。CA 在签名之前会进行一些验证。对于一些证书类型（LCTT 译注： 域名证实 Domain Validated （DV） 类型），CA 只验证申请者的确是 CSR 中列出主机名对应域名的控制者（例如通过邮件验证，让申请者完成指定的域名解析）。对于另一些证书类型 （LCTT 译注：链接中提到 扩展证实 Extended Validated （EV）类型，其实还有 OV Organization Validated 类型），CA 还会检查相关法律文书，例如公司营业执照等。一旦验证完成，CA（一般在申请者付费后）会从 CSR 中取出数据（即公钥和身份信息），使用 CA 自己的私钥进行签名，创建一个（签名）证书并发送给申请者。申请者将该证书部署在网站服务器上，当用户使用 HTTPS （或其它基于 TLS 加密的协议）与服务器通信时，该证书被分发给用户。当用户访问该网站时，浏览器获取该证书，接着检查证书中的主机名是否与当前正在连接的网站一致（下文会详细说明），核验 CA 签名有效性。如果其中一步验证不通过，浏览器会给出安全警告并切断与网站的连接。反之，如果验证通过，浏览器会使用证书中的公钥来核验该服务器发送的签名信息，确认该服务器持有该证书的私钥。有几种算法用于协商后续通信用到的 共享密钥 shared secret key ，其中一种也用到了服务器发送的签名信息。 密钥交换 key exchange 算法不在本文的讨论范围，可以参考这个视频，其中仔细说明了一种密钥交换算法。建立信任你可能会问，“如果 CA 使用其私钥对证书进行签名，也就意味着我们需要使用 CA 的公钥验证证书。那么 CA 的公钥从何而来，谁对其进行签名呢？” 答案是 CA 对自己签名！可以使用证书公钥对应的私钥，对证书本身进行签名！这类签名证书被称为是 自签名的 self-signed ；在 PKI 体系下，这意味着对你说“相信我”。（为了表达方便，人们通常说用证书进行了签名，虽然真正用于签名的私钥并不在证书中。）通过遵守浏览器和操作系统供应商建立的规则，CA 表明自己足够可靠并寻求加入到浏览器或操作系统预装的一组自签名证书中。这些证书被称为“ 信任锚 trust anchor ”或 CA 根证书 root CA certificate ，被存储在根证书区，我们 约定 implicitly 信任该区域内的证书。CA 也可以签发一种特殊的证书，该证书自身可以作为 CA。在这种情况下，它们可以生成一个证书链。要核验证书链，需要从“信任锚”（也就是 CA 根证书）开始，使用当前证书的公钥核验下一层证书的签名（或其它一些信息）。按照这个方式依次核验下一层证书，直到证书链底部。如果整个核验过程没有问题，信任链也建立完成。当向 CA 付费为网站签发证书时，实际购买的是将证书放置在证书链下的权利。CA 将卖出的证书标记为“不可签发子证书”，这样它们可以在适当的长度终止信任链（防止其继续向下扩展）。为何要使用长度超过 2 的信任链呢？毕竟网站的证书可以直接被 CA 根证书签名。在实际应用中，很多因素促使 CA 创建 中间 CA 证书 intermediate CA certificate ，最主要是为了方便。由于价值连城，CA 根证书对应的私钥通常被存放在特定的设备中，一种需要多人解锁的 硬件安全模块 hardware security module （HSM），该模块完全离线并被保管在配备监控和报警设备的地下室中。 CA/浏览器论坛 CAB Forum, CA/Browser Forum 负责管理 CA，要求任何与 CA 根证书（LCTT 译注：就像前文提到的那样，这里是指对应的私钥）相关的操作必须由人工完成。设想一下，如果每个证书请求都需要员工将请求内容拷贝到保密介质中、进入地下室、与同事一起解锁 HSM、（使用 CA 根证书对应的私钥）签名证书，最后将签名证书从保密介质中拷贝出来；那么每天为大量网站签发证书是相当繁重乏味的工作。因此，CA 创建内部使用的中间 CA，用于证书签发自动化。如果想查看证书链，可以在 Firefox 中点击地址栏的锁型图标，接着打开页面信息，然后点击“安全”面板中的“查看证书”按钮。在本文写作时，opensource.com 使用的证书链如下：DigiCert High Assurance EV Root CA DigiCert SHA2 High Assurance Server CA opensource.com中间人我之前提到，浏览器需要核验证书中的主机名与已经建立连接的主机名一致。为什么需要这一步呢？要回答这个问题，需要了解所谓的 中间人攻击 man-in-the-middle, MIMT 。有一类网络攻击可以让攻击者将自己置身于客户端和服务端中间，冒充客户端与服务端连接，同时冒充服务端与客户端连接。如果网络流量是通过 HTTPS 传输的，加密的流量无法被窃听。此时，攻击者会创建一个代理，接收来自受害者的 HTTPS 连接，解密信息后构建一个新的 HTTPS 连接到原始目的地（即服务端）。为了建立假冒的 HTTPS 连接，代理必须返回一个攻击者具有对应私钥的证书。攻击者可以生成自签名证书，但受害者的浏览器并不会信任该证书，因为它并不是根证书库中的 CA 根证书签发的。换一个方法，攻击者使用一个受信任 CA 签发但主机名对应其自有域名的证书，结果会怎样呢？再回到银行的那个例子，我们是银行柜员，一位男性顾客进入银行要求从 Jane Doe 的账户上取钱。当被要求提供身份证明时，他给出了 Joe Smith 的有效驾驶执照。如果这个交易可以完成，我们无疑会被银行开除。类似的，如果检测到证书中的主机名与连接对应的主机名不一致，浏览器会给出类似“连接不安全”的警告和查看更多内容的选项。在 Firefox 中，这类错误被标记为 SSL_ERROR_BAD_CERT_DOMAIN。我希望你阅读完本文起码记住这一点：如果看到这类警告，不要无视它们！它们出现意味着，或者该网站配置存在严重问题（不推荐访问），或者你已经是中间人攻击的潜在受害者。总结虽然本文只触及了 PKI 世界的一些皮毛，我希望我已经为你展示了便于后续探索的大致蓝图。密码学和 PKI 是美与复杂性的结合体。越深入研究，越能发现更多的美和复杂性，就像分形那样。via: https://opensource.com/article/18/7/private-keys作者：Alex Wood 选题：lujun9972 译者：pinewall 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
学习密码学背后的基本概念，主要是保密性、完整性和身份认证。安全通信正快速成为当今互联网的规范。从 2018 年 7 月起，Google Chrome 将对全部使用 HTTP 传输（而不是 HTTPS 传输）的站点开始显示“不安全”警告。虽然密码学已经逐渐变广为人知，但其本身并没有变得更容易理解。Let's Encrypt 设计并实现了一套令人惊叹的解决方案，可以提供免费安全证书和周期性续签；但如果不了解底层概念和缺陷，你也不过是加入了类似“ 货物崇拜 cargo cult ”的技术崇拜的程序员大军。安全通信的特性密码学最直观明显的目标是 保密性 confidentiality ： 消息 message 传输过程中不会被窥探内容。为了保密性，我们对消息进行加密：对于给定消息，我们结合一个 密钥 key 生成一个无意义的乱码，只有通过相同的密钥逆转加密过程（即解密过程）才能将其转换为可读的消息。假设我们有两个朋友 Alice 和 Bob，以及他们的 八卦 nosy 邻居 Eve。Alice 加密类似 "Eve 很讨厌" 的消息，将其发送给 Bob，期间不用担心 Eve 会窥探到这条消息的内容。对于真正的安全通信，保密性是不够的。假如 Eve 收集了足够多 Alice 和 Bob 之间的消息，发现单词 “Eve” 被加密为 "Xyzzy"。除此之外，Eve 还知道 Alice 和 Bob 正在准备一个派对，Alice 会将访客名单发送给 Bob。如果 Eve 拦截了消息并将 “Xyzzy” 加到访客列表的末尾，那么她已经成功的破坏了这个派对。因此，Alice 和 Bob 需要他们之间的通信可以提供 完整性 integrity ：消息应该不会被篡改。而且我们还有一个问题有待解决。假如 Eve 观察到 Bob 打开了标记为“来自 Alice”的信封，信封中包含一条来自 Alice 的消息“再买一加仑冰淇淋”。Eve 看到 Bob 外出，回家时带着冰淇淋，这样虽然 Eve 并不知道消息的完整内容，但她对消息有了大致的了解。Bob 将上述消息丢弃，但 Eve 找出了它并在下一周中的每一天都向 Bob 的邮箱中投递一封标记为“来自 Alice”的信封，内容拷贝自之前 Bob 丢弃的那封信。这样到了派对的时候，冰淇淋严重超量；派对当晚结束后，Bob 分发剩余的冰淇淋，Eve 带着免费的冰淇淋回到家。消息是加密的，完整性也没问题，但 Bob 被误导了，没有认出发信人的真实身份。 身份认证 Authentication 这个特性用于保证你正在通信的人的确是其声称的那样。信息安全还有其它特性，但保密性、完整性和身份验证是你必须了解的三大特性。加密和加密算法加密都包含哪些部分呢？首先，需要一条消息，我们称之为 明文 plaintext 。接着，需要对明文做一些格式上的初始化，以便用于后续的加密过程（例如，假如我们使用 分组加密算法 block cipher ，需要在明文尾部填充使其达到特定长度）。下一步，需要一个保密的比特序列，我们称之为 密钥 key 。然后，基于私钥，使用一种加密算法将明文转换为 密文 ciphertext 。密文看上去像是随机噪声，只有通过相同的加密算法和相同的密钥（在后面提到的非对称加密算法情况下，是另一个数学上相关的密钥）才能恢复为明文。（LCTT 译注：cipher 一般被翻译为密码，但其具体表达的意思是加密算法，这里采用加密算法的翻译）加密算法使用密钥加密明文。考虑到希望能够解密密文，我们用到的加密算法也必须是 可逆的 reversible 。作为简单示例，我们可以使用 XOR。该算子可逆，而且逆算子就是本身（P ^ K = C; C ^ K = P），故可同时用于加密和解密。该算子的平凡应用可以是 一次性密码本 one-time pad ，不过一般而言并不可行。但可以将 XOR 与一个基于单个密钥生成 任意随机数据流 arbitrary stream of random data 的函数结合起来。现代加密算法 AES 和 Chacha20 就是这么设计的。我们把加密和解密使用同一个密钥的加密算法称为 对称加密算法 symmetric cipher 。对称加密算法分为 流加密算法 stream ciphers 和分组加密算法两类。流加密算法依次对明文中的每个比特或字节进行加密。例如，我们上面提到的 XOR 加密算法就是一个流加密算法。流加密算法适用于明文长度未知的情形，例如数据从管道或 socket 传入。RC4 是最为人知的流加密算法，但在多种不同的攻击面前比较脆弱，以至于最新版本 （1.3）的 TLS （“HTTPS” 中的 “S”）已经不再支持该加密算法。Efforts 正着手创建新的加密算法，候选算法 ChaCha20 已经被 TLS 支持。分组加密算法对固定长度的分组，使用固定长度的密钥加密。在分组加密算法领域，排行第一的是 先进加密标准 Advanced Encryption Standard （AES），使用的分组长度为 128 比特。分组包含的数据并不多，因而分组加密算法包含一个工作模式，用于描述如何对任意长度的明文执行分组加密。最简单的工作模式是 电子密码本 Electronic Code Book （ECB），将明文按分组大小划分成多个分组（在必要情况下，填充最后一个分组），使用密钥独立的加密各个分组。这里我们留意到一个问题：如果相同的分组在明文中出现多次（例如互联网流量中的 GET / HTTP/1.1 词组），由于我们使用相同的密钥加密分组，我们会得到相同的加密结果。我们的安全通信中会出现一种 模式规律 pattern ，容易受到攻击。因此还有很多高级的工作模式，例如 密码分组链接 Cipher Block Chaining （CBC），其中每个分组的明文在加密前会与前一个分组的密文进行 XOR 操作，而第一个分组的明文与一个随机数构成的初始化向量进行 XOR 操作。还有其它一些工作模式，在安全性和执行速度方面各有优缺点。甚至还有 Counter (CTR) 这种工作模式，可以将分组加密算法转换为流加密算法。除了对称加密算法，还有 非对称加密算法 asymmetric ciphers ，也被称为 公钥密码学 public-key cryptography 。这类加密算法使用两个密钥：一个 公钥 public key ，一个 私钥 private key 。公钥和私钥在数学上有一定关联，但可以区分二者。经过公钥加密的密文只能通过私钥解密，经过私钥加密的密文可以通过公钥解密。公钥可以大范围分发出去，但私钥必须对外不可见。如果你希望和一个给定的人通信，你可以使用对方的公钥加密消息，这样只有他们的私钥可以解密出消息。在非对称加密算法领域，目前 RSA) 最具有影响力。非对称加密算法最主要的缺陷是，它们是 计算密集型 computationally expensive 的。那么使用对称加密算法可以让身份验证更快吗？如果你只与一个人共享密钥，答案是肯定的。但这种方式很快就会失效。假如一群人希望使用对称加密算法进行两两通信，如果对每对成员通信都采用单独的密钥，一个 20 人的群体将有 190 对成员通信，即每个成员要维护 19 个密钥并确认其安全性。如果使用非对称加密算法，每个成员仅需确保自己的私钥安全并维护一个公钥列表即可。非对称加密算法也有加密数据长度限制。类似于分组加密算法，你需要将长消息进行划分。但实际应用中，非对称加密算法通常用于建立 机密 confidential 、 已认证 authenticated 的 通道 channel ，利用该通道交换对称加密算法的共享密钥。考虑到速度优势，对称加密算法用于后续的通信。TLS 就是严格按照这种方式运行的。基础安全通信的核心在于随机数。随机数用于生成密钥并为 确定性过程 deterministic processes 提供不可预测性。如果我们使用的密钥是可预测的，那我们从一开始就可能受到攻击。计算机被设计成按固定规则操作，因此生成随机数是比较困难的。计算机可以收集鼠标移动或 键盘计时 keyboard timings 这类随机数据。但收集随机性（也叫 信息熵 entropy ）需要花费不少时间，而且涉及额外处理以确保 均匀分布 uniform distribution 。甚至可以使用专用硬件，例如 熔岩灯 lava lamps 墙等。一般而言，一旦有了一个真正的随机数值，我们可以将其用作 种子 seed ，使用 密码安全的伪随机数生成器 cryptographically secure pseudorandom number generator 生成随机数。使用相同的种子，同一个随机数生成器生成的随机数序列保持不变，但重要的是随机数序列是无规律的。在 Linux 内核中，/dev/random 和 /dev/urandom 工作方式如下：从多个来源收集信息熵，进行 无偏处理 remove biases ，生成种子，然后生成随机数，该随机数可用于 RSA 密钥生成等。其它密码学组件我们已经实现了保密性，但还没有考虑完整性和身份验证。对于后两者，我们需要使用一些额外的技术。首先是 密码散列函数 crytographic hash function ，该函数接受任意长度的输入并给出固定长度的输出（一般称为 摘要 digest ）。如果我们找到两条消息，其摘要相同，我们称之为 碰撞 collision ，对应的散列函数就不适合用于密码学。这里需要强调一下“找到”：考虑到消息的条数是无限的而摘要的长度是固定的，那么总是会存在碰撞；但如果无需海量的计算资源，我们总是能找到发生碰撞的消息对，那就令人比较担心了。更严重的情况是，对于每一个给定的消息，都能找到与之碰撞的另一条消息。另外，哈希函数必须是 单向的 one-way ：给定一个摘要，反向计算对应的消息在计算上不可行。相应的，这类条件被称为 碰撞阻力 collision resistance 、 第二原象抗性 second preimage resistance 和 原象抗性 preimage resistance 。如果满足这些条件，摘要可以用作消息的指纹。理论上不存在具有相同指纹的两个人，而且你无法使用指纹反向找到其对应的人。如果我们同时发送消息及其摘要，接收者可以使用相同的哈希函数独立计算摘要。如果两个摘要相同，可以认为消息没有被篡改。考虑到 SHA-1 已经变得有些过时，目前最流行的密码散列函数是 SHA-256。散列函数看起来不错，但如果有人可以同时篡改消息及其摘要，那么消息发送仍然是不安全的。我们需要将哈希与加密算法结合起来。在对称加密算法领域，我们有 消息认证码 message authentication codes （MAC）技术。MAC 有多种形式，但 哈希消息认证码 hash message authentication codes （HMAC） 这类是基于哈希的。HMAC 使用哈希函数 H 处理密钥 K、消息 M，公式为 H(K + H(K + M))，其中 + 代表 连接 concatenation 。公式的独特之处并不在本文讨论范围内，大致来说与保护 HMAC 自身的完整性有关。发送加密消息的同时也发送 MAC。Eve 可以任意篡改消息，但一旦 Bob 独立计算 MAC 并与接收到的 MAC 做比较，就会发现消息已经被篡改。在非对称加密算法领域，我们有 数字签名 digital signatures 技术。如果使用 RSA，使用公钥加密的内容只能通过私钥解密，反过来也是如此；这种机制可用于创建一种签名。如果只有我持有私钥并用其加密文档，那么只有我的公钥可以用于解密，那么大家潜在的承认文档是我写的：这是一种身份验证。事实上，我们无需加密整个文档。如果生成文档的摘要，只要对这个指纹加密即可。对摘要签名比对整个文档签名要快得多，而且可以解决非对称加密存在的消息长度限制问题。接收者解密出摘要信息，独立计算消息的摘要并进行比对，可以确保消息的完整性。对于不同的非对称加密算法，数字签名的方法也各不相同；但核心都是使用公钥来检验已有签名。汇总现在，我们已经有了全部的主体组件，可以用其实现一个我们期待的、具有全部三个特性的 体系 system 。Alice 选取一个保密的对称加密密钥并使用 Bob 的公钥进行加密。接着，她对得到的密文进行哈希并使用其私钥对摘要进行签名。Bob 接收到密文和签名，一方面独立计算密文的摘要，另一方面使用 Alice 的公钥解密签名中的摘要；如果两个摘要相同，他可以确信对称加密密钥没有被篡改且通过了身份验证。Bob 使用私钥解密密文得到对称加密密钥，接着使用该密钥及 HMAC 与 Alice 进行保密通信，这样每一条消息的完整性都得到保障。但该体系没有办法抵御消息重放攻击（我们在 Eve 造成的冰淇淋灾难中见过这种攻击）。要解决重放攻击，我们需要使用某种类型的“ 握手 handshake ”建立随机、短期的 会话标识符 session identifier 。密码学的世界博大精深，我希望这篇文章能让你对密码学的核心目标及其组件有一个大致的了解。这些概念为你打下坚实的基础，让你可以继续深入学习。感谢 Hubert Kario、Florian Weimer 和 Mike Bursell 在本文写作过程中提供的帮助。via: https://opensource.com/article/18/5/cryptography-pki作者：Alex Wood 选题：lujun9972 译者：pinewall 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出