读《图解密码技术》(三):密钥、随机数和应用技术

原创文章,转载请注明:转载自Keegan小钢javascript

并标明原文连接:http://keeganlee.me/post/reading/20160722java

微信订阅号:keeganlee_me程序员

写于2016-07-22算法


读《图解密码技术》(一):密码安全

读《图解密码技术》(二):认证服务器

读《图解密码技术》(三):密钥、随机数和应用技术微信


最后一篇了,若是还没看过前两篇的,最好先翻回去看看,由于这最后一篇的内容是创建在前两篇的基础之上的。本篇的内容包括密钥、随机数、PGP、SSL/TLS,最后再讲讲密码技术的现状和局限性,以及简单介绍一下量子密码和量子计算机。网络

密钥

在使用对称密码、公钥密码、消息认证码、数字签名等密码技术时,都须要密钥。密钥长度通常不能过短,过短意味着密钥空间过小,那么,进行暴力破解就很容易。框架

DES的密钥长度为56比特(7字节),密钥空间为2^56,在现有的计算能力下,仍是比较容易被暴力破解的。三重DES的DES-EDE3的密钥长度为168比特(21字节),是DES的密钥长度的三倍多,可是密钥空间可不是三倍这么简单,DES-EDE3的密钥空间为2^168,整整是DES密钥空间的2^112倍,这么大的密钥空间,以现有的计算能力,还没法在现实的时间里被暴力破解。AES的密钥长度则能够从12八、192和256比特中进行选择,三者的密钥空间也是不小的。dom

密钥和明文实际上是等价的,由于对攻击者来讲,获得密钥就等价于获得明文。

各类不一样的密钥

从前两篇文章咱们就知道,密钥分不少种类,这里咱们作一下整理。

在对称密码中,加密和解密使用的是相同的共享密钥。而在公钥密码中,加密用的是公钥,解密用的则是私钥,相对应的公钥和私钥组为密钥对。消息认证码使用的也是共享密钥。而数字签名使用的和公钥密码同样是密钥对,用私钥签名,用公钥验证签名。混合密码系统中还使用了一次性密钥,称为会话密钥。而相对于每次通讯都更换的会话密钥,一直被重复使用的密码则称为主密钥。用于加密内容的密钥称为CEK(Contents Encrypting Key,内容加密密钥);相对地,用于加密密钥的密钥则称为KEK(Key Encrypting Key,密钥加密密钥)。CEK 和 KEK 的用法能够以下图所示:

在不少状况下,会话密钥都是被做为 CEK 使用的,而主密钥则是被做为 KEK 使用的。

密钥的管理

生成密钥最好的方法就是使用真正的随机数,由于密钥须要具有不可预测性。不过,通常咱们都是使用伪随机数生成器来生成密钥。另外,密码学用途的伪随机数生成器必须是专门针对密码学用途而设计的。毕竟,生成伪随机数的算法不少,但有些并不具有不可预测性。

有时咱们也会使用容易记住的口令(password 或 passphrase)来生成密钥。passphrase 指的是一种由多个单词组成的较长的 passwrod,在此将二者统称为口令。严格来讲,不多直接用口令来做为密钥使用,通常都是将口令输入单向散列函数,而后将获得的散列值做为密钥使用。而在使用口令生成密钥时,为了防止字典攻击,须要在口令上面附加一串称为(salt)的随机数,而后再将其输入单向散列函数。这种方法称为“基于口令的密码”(Password Based Encryption, PBE)。关于 PBE 稍后再详细介绍。

对于共享密钥,就会存在密钥配送问题。在密码篇就提到几种解决方案:事先共享密钥使用密钥分配中心使用公钥密码Diffie-Hellman密钥交换。关于Diffie-Hellman密钥交换的原理,以前的文章没讲,在本篇稍后会详细介绍。

为了提升通讯的机密性,还能够采用密钥更新(key updating)的方法。这种方法就是在使用共享密钥进行通讯的过程当中,按期改变密钥。例如,在更新密钥时,发送者和接收者使用单向散列函数计算当前密钥的散列值,并将这个散列值用做新的密钥。简单说,就是用当前密钥的散列值做为下一个密钥

除了只使用一次的会话密钥,其余密钥基本都须要考虑保存密钥的问题。尤为对于共享密钥来讲,不少应用都须要将密钥保存在客户端,例如移动App,要么将密钥硬编码在代码里,或者保存在文件中,但不管哪一种方式,应用一旦被反编译,密钥就存在泄漏的风险。以防密钥被盗,可使用将密钥加密后保存的方法。但要将密钥加密,必然须要另外一个密钥,即 KEK。那么,KEK 又如何保存?这问题还真很差解决。不过,对密钥进行加密的方法却能够减小须要保管的密钥数量。好比,假设平台系统接入了10万个应用,每一个应用都有一个本身的密钥,即系统须要保管10万个密钥。那么,用 KEK 对这10万个密钥进行加密,这样的话只要保管这一个 KEK 就能够了。便是说,不须要确保多个密钥(CEK)的机密性,而只须要确保一个密钥(KEK)的机密性就能够了。这和认证机构的层级化很是类似。在后者中,咱们不须要信任多个认证机构,而只须要信任一个根 CA 就能够了。

Diffie-Hellman密钥交换

经过Diffie-Hellman密钥交换算法,通讯双方仅经过交换一些能够公开的信息就可以生成出共享的秘密数字,而这一秘密数字就能够被用做对称密码的密钥。虽然这种方法名字叫“密钥交换”,但实际上双方并无真正交换密钥,而是经过计算生成出了一个相同的共享密钥。所以,这种方法也称为 Diffie-Hellman密钥协商

Diffie-Hellman密钥交换的步骤以下:

  1. Alice 向 Bob 发送两个质数 P 和 G

    P 必须是一个很是大的质数,而 G 则是一个和 P 相关的数,称为生成元(generator)。G 能够是一个较小的数字。

  2. Alice 生成一个随机数 A

    A 是一个 1 ~ P-2 之间的整数。这个数是一个只有 Alice 知道的秘密数字。

  3. Bob 生成一个随机数 B

    B 也是一个 1 ~ P-2 之间的整数。这个数是一个只有 Bob 才知道的秘密数字。

  4. Alice 将 G^A mod P 计算结果的数发送给 Bob

  5. Bob 将 G^B mod P 计算结果的数发送给 Alice

  6. Alice 用 Bob 发过来的数计算 A 次方并求 mod P

    这个数就是共享密钥。Alice 计算的密钥 = (G^B mod P)^A mod P = G^(A*B) mod P

  7. Bob 用 Alice 发过来的数计算 B 次方并求 mod P

    Bob 计算的密钥 = (G^A mod P)^B mod P = G^(A*B) mod P = Alice 计算的密钥。可见两方计算的密钥是相等的。

关于第1步提到的生成元是什么呢?先来看一张表,假设 P = 13:

其中,二、六、七、11都是13的生成元。这几个数有什么性质呢?从上表能够发现,这几个数的乘方结果中都出现了1~12的所有整数。也就是说,P 的生成元的乘方结果与 1 ~ P-1 中的数字是一一对应的。正是由于具备这样一一对应的关系,Alice 才可以从 1 ~ P-2 的范围中随机选择一个数字(之因此不能选择 P-1,是由于 G^(P-1) mod P 的值必定是等于1的)。

最后,须要清楚,针对Diffie-Hellman密钥交换是能够发动中间人攻击的。而为了防止中间人攻击,可使用数字签名、证书等方法来应对。

基于口令的密码(PBE)

基于口令的密码(Password Based Encryption,PBE)就是一种根据口令生成密钥并用该密钥进行加密的方法。

PBE 的加密能够用下图来表示:

主要有三个步骤:

  1. 生成 KEK

    首先,经过伪随机数生成器生成一个被称为(salt)的随机数。而后,将盐和口令一块儿输入单向散列函数,输出的结果就是 KEK。盐是一种用于防护字典攻击的机制。

  2. 生成会话密钥并加密

    会话密钥 CEK 也是经过伪随机数生成器来生成,生成以后使用 KEK 对其进行加密,而后将加密后的会话密钥和盐一块儿保存在安全的地方。

  3. 加密消息

    最后,使用 CEK 对消息进行加密。

而 PBE 解密的过程则以下图:

解密主要也是有三个步骤:

  1. 重建KEK

    将以前保存下来的盐和口令一块儿输入单向散列函数,获得的散列值就是 KEK 了。

  2. 解密会话密钥

    再将以前保存下来的已加密的会话密钥用 KEK 进行解密,就能获得会话密钥 CEK 了。

  3. 解密消息

    最后,用已解密的 CEK 对密文进行解密便可。

另外,在生成 KEK 时,经过屡次使用单向散列函数能够提升安全性。

随机数

有哪些场景使用到随机数呢?主要可能有如下这些:

  • 生成密钥
  • 生成密钥对
  • 生成初始化向量(IV)
  • 生成nonce
  • 生成盐

随机数的性质主要分为三类:

  • 随机性:不存在统计学误差,是彻底杂乱的数列。
  • 不可预测性:不能从过去的数列推测出下一个出现的数。
  • 不可重现性:除非将数列自己保存下来,不然不能重现相同的数列。

上面三个性质中,越往下就越严格。具有随机性,不表明必定具有不可预测性。具有不可预测性的数列,则必定具有随机性。具有不可重现性的数列,也必定具有不可预测性和随机性。在书中,将这三个性质的随机数按顺序分别命名为“弱伪随机数”、“强伪随机数”和“真随机数”。

伪随机数生成器

随机数能够经过硬件来生成,也能够经过软件来生成。经过硬件生成的随机数列通常都是真随机数,是从不可重现的物理现象中获取信息而生成数列的,好比周围的温度和声音的变化、用户移动鼠标的位置信息、键盘输入的时间间隔、放射线测量仪的输出值等。像这样的硬件设备称为随机数生成器(Random Number Generator,RNG)。而生成随机数的软件则称为伪随机数生成器(Pseudo Random Number Generator,PRNG)。由于仅靠软件没法生成真随机数,由于要加上一个“伪”字。

伪随机数生成器具备“内部状态”,并根据外部输入的“种子”来生成伪随机数列,以下图:

伪随机数生成器的内部状态,是指伪随机数生成器所管理的内存中的数值。这个数值在每次生成随机数后都会改变。而种子是用来初始化内部状态的。伪随机数生成器是公开的,但种子是须要保密的,这就好像密码算法是公开的,但密钥是保密的。

具体的伪随机数生成器

具体的伪随机数生成器有不少,书中介绍了五种:杂乱的方法、线性同余法、单向散列函数法、密码法、ANSI X9.17。

  • 杂乱的方法

    杂乱的方法就是使用杂乱无章的算法来生成随机数,但这种方法其实并不可取。一是由于复杂算法所生成的数列大多数具备很短的周期(即短数列的不断重复);二是由于若是程序员不可以理解算法的详细内容,那么就没法判断所生成的随机数是否具有不可预测性。

  • 线性同余法

    线性同余法就是将当前的伪随机数值乘以 A 再加上 C,而后将除以 M 获得的余数做为下一个伪随机数。其中,A、C、M都是常量,且 A 和 C 须要小于 M。C 语言的库函数 rand,以及Java 的 Random 类,都采用了线性同余法。线性同余法并不具有不可预测性,所以不能够用于密码技术。

  • 单向散列函数法

    使用单向散列函数能够编写出具有不可预测性的伪随机数列(即强伪随机数)的伪随机数生成器。单向散列函数的单向性是支撑伪随机数生成器不可预测性的基础。

  • 密码法

    也可使用密码来编写可以生成强伪随机数的伪随机数生成器。既可使用 AES 等对称密码,也可使用 RSA 等公钥密码。密码的机密性是支撑伪随机数生成器不可预测性的基础。

  • ANSI X9.17

    ANSI X9.17 伪随机数生成器的结构则有点复杂,PGP 密码软件就使用了这种方法。

PGP

PGP 将多种密码技术进行了完美的组合,其具有了现代密码软件所必需的几乎所有功能,包括但不限于:对称密码、公钥密码、数字签名、单向散列函数、证书、压缩、大文件的拆分和拼合、钥匙串管理等。

生成密钥对

要在 PGP 中进行加密和数字签名,须要先生成本身的密钥对。下图展现了从命令行生成密钥的过程,其中,粗体为用户输入的内容:

加密和解密

使用 PGP 进行加密的过程以下图所示:

而解密的过程则以下:

PGP 的私钥是保存在用户的钥匙串中的。另外,私钥都是以加密状态保存的,并在保存时使用了基于口令的密码(PBE)。

生成和验证数字签名

生成数字签名的过程以下图:

而验证签名的过程则以下图:

生成数字签名并加密以及解密并验证数字签名

如何将密码和数字签名进行组合,下面两张图是整本书最复杂的,但它只不过是将以前讲解的内容组合起来了而已。

下图是生成数字签名并加密的过程:

而下图则是解密并验证数字签名的过程:

信任网

如何确认公钥的合法性?前面介绍的证书是一种方法。对公钥的信任是创建在对认证机构的信任的基础之上的。不过,PGP 却没有使用认证机构,而是采用了一种叫作信任网(也称为信任圈好友圈)的方法。信任网的要点是“不依赖认证机构,而是创建每一个人之间的信任关系”。换言之,就是可以本身决定要信任哪些公钥。

PGP 当初的设计目的是在连国家都不可信的状况下依然可以使用,所以它并不关心有没有可信的认证机构,而是采用了“由用户本身来决定信任谁”这样的设计。

须要注意,“公钥是否合法”与“全部者是否可信”是两个不一样的问题,由于尽管公钥合法,其全部者也能够是不可信的。例如,Alice认为从Bob那得到的公钥是合法的,由于这个公钥是Bob当面交给Alice的。可是Alice不信任Bob在数字签名上的判断能力,即使Bob对其余的公钥进行了数字签名,Alice也会怀疑Bob是否真的进行了本人确认。

在 PGP 中,信任级别能够分为四种:绝对信任、彻底信任、有限信任和不信任。

SSL/TLS

SSL/TLS也是综合运用了对称密码、公钥密码、消息认证码、数字签名、伪随机数生成器等密码技术。而咱们知道SSL/TLS最普遍的应用就是套接在HTTP上,但实际上,SSL/TLS还能够套接在其余网络协议之上的,例如,SMTP 和 POP3 之类的电子邮件协议。由于如今普遍使用的是TLS协议,所以下文只以TLS协议为主。

TLS安全协议可分为两层:TLS记录协议TLS握手协议。TLS记录协议在TLS握手协议的下层,负责数据封装、压缩、加密等功能。而TLS握手协议则用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换密钥等。TLS握手协议又分为4个子协议:握手协议、密码规格变动协议、警告协议和应用数据协议。TLS协议的层次结构以下图:

TLS记录协议

TLS记录协议的处理过程以下图:

首先,消息被分割成多个片断,而后分别对每一个片断进行压缩。压缩算法须要与通讯对象协商决定。接下来,通过压缩的片断会被加上消息认证码,这就能够保证完整性,并进行数据的认证。同时,为了防止重放攻击,在计算消息认证码时,还加上了片断的编号。单向散列函数的算法,以及消息认证码所使用的密钥都须要与通讯对象协商决定。再接下来,就是加密了。加密使用CBC模式,CBC模式的初始化向量(IV)经过主密码生成,而对称密码的算法和共享密钥也是须要与通讯对象协商决定。最后,密文再加上数据类型、版本号、压缩后的长度组成的报头就是最终的报文数据。其中,数据类型为TLS握手协议中的4个子协议之一。

TLS握手协议

TLS握手协议可分为4个子协议,其中,握手协议是最复杂的一个子协议,其过程以下图:

1. ClientHello(客户端->服务器)

客户端向服务器发送ClientHello消息,消息内容主要包括:可用的版本号、当前时间、客户端随机数、会话ID、可用的密码套件清单、可用的压缩方式清单。复制代码

2. ServerHello(服务器->客户端)

对于客户端发送的ClientHello消息,服务器会返回一个ServerHello消息,消息内容主要包括:使用的版本号、当前时间、服务器随机数、会话ID、使用的密码套件、使用的压缩方式。这一步肯定了通讯中使用的“版本号”、“密码套件”和“压缩方式”。复制代码

3. Certificate(服务器->客户端)

服务器再向客户端发送Certificate消息,主要是**证书清单**。首先发送的是服务器的证书,而后会按顺序发送对服务器证书签名的认证机构的证书。复制代码

4. ServerKeyExchange(服务器->客户端)

当Certificate消息不足以知足需求时,服务器会向客户端发送ServerKeyExchange消息。具体所发送的消息内容会根据所使用的密码套件而有所不一样。复制代码

5. CertificateRequest(服务器->客户端)

CertificateRequest消息用于服务器向客户端请求证书,这是为了进行**客户端认证**。消息内容还包括:服务器可以理解的证书类型清单和认证机构名称清单。当不使用客户端认证时,不会发送CertificateRequest消息。复制代码

6. ServerHelloDone(服务器->客户端)

服务器发送ServerHelloDone消息则表示从ServerHello消息开始的一系列消息的结束。复制代码

7. Certificate(客户端->服务器)

当服务器发送了CertificateRequest消息时,则客户端会发送Certificate消息,将本身的证书同消息一块儿发送给服务器。若是服务器没有发送CertificateRequest消息,客户端则不会发送Certificate消息。复制代码

8. ClientKeyExchange(客户端->服务器)

客户端发送ClientKeyExchange消息。当密码套件中保护RSA时,会随消息一块儿发送**通过加密的预备主密码**。当密码套件中包含Diffie-Hellman密钥交换时,会随消息一块儿发送**Diffie-Hellman的公开值**。预备主密码是由客户端生成的随机数,以后会被用做生成主密码的种子。根据预备主密码,服务器和客户端会计算出相同的**主密码**,而后再根据主密码生成:对称密码的密钥、消息认证码的密钥、对称密码的CBC模式中使用的初始化向量(IV)。复制代码

9. CertificateVerify(客户端->服务器)

客户端只有在服务器发送CertificateRequest消息时才会发送CertificateVerify消息。这个消息的目的是向服务器证实本身的确持有客户端证书的私钥。为了实现这一目的,客户端会计算“主密码”和“握手协议中传送的消息”的散列值,并加上本身的数字签名后发送给服务器。复制代码

10. ChangeCipherSpec(客户端->服务器)

客户端发送ChangeCipherSpec消息表示要切换密码。实际上,这不是握手协议的消息,而是密码规格变动协议的消息。在ChangeCipherSpec消息以前,客户端和服务器之间以及交换了全部关于密码套件的信息,所以在收到这一消息时,客户端和服务器会同时切换密码。在这一消息以后,TLS记录协议就开始使用双方协商决定的密码通讯方式了。复制代码

11. Finished(客户端->服务器)

客户端发送Finished消息表示握手协议到此结束。这个消息实际上是使用切换后的密码套件来发送的。实际负责加密操做的是TLS记录协议。复制代码

12. ChangeCipherSpec(服务器->客户端)

此次轮到服务器发送ChangeCipherSpec消息了,代表服务器要切换密码了。复制代码

13. Finished(服务器->客户端)

服务器也一样发送Finished消息代表握手协议到此结束。这个消息一样使用切换后的密码套件来发送。实际负责加密操做的也是TLS记录协议。复制代码

14. 切换至应用数据协议

在此以后,客户端和服务器会使用应用数据协议和TLS记录协议进行密码通讯。复制代码

从结果来看,握手协议完成了下列操做:

  • 客户端得到了服务器的合法公钥,完成了服务器认证。
  • 服务器得到了客户端的合法公钥,完成了客户端认证(当须要客户端认证时)。
  • 客户端和服务器生成了密码通讯中使用的共享密钥。
  • 客户端和服务器生成了消息认证码中使用的共享密钥。

除了握手协议,其余3各子协议都很简单。密码规格变动协议用于密码切换的同步。简单地说,就跟向对方喊“一、二、3!”差很少。当协议中途发生错误时,就会经过警告协议传达给对方。警告协议负责在发生错误时将错误传达给对方。若是没有发生错误,则会使用应用数据协议来进行通讯。应用数据协议用于和通讯对象之间传送应用数据。当TLS套接在HTTP时,HTTP的请求和相应就会经过TLS的应用数据协议和TLS记录协议来进行传送。

密码技术与现实社会

前面讲到的6种基本的密码技术可整理成下图:

书中屡次使用了框架这个说法。框架的特色就是可以对其中做为组成元素的技术进行替换,就像更好零件同样。例如,消息认证码算法HMAC的设计就容许对单向散列函数的算法进行替换。在PGP中,对称密码、公钥密码、单向散列函数等都是能够替换的。在SSL/TLS中,客户端和服务器能够经过握手协议进行通讯,并当场决定所使用的密码套件。使用框架可以提升密码技术系统的重用性,也可以提升系统的强度。经过将单独的密码技术像零件同样组合起来,并根据须要进行替换,可以实现更长期的、更高的安全性。

另外,全部密码技术其实也能够当作是一种“压缩技术”,以下表所示:

量子密码和量子计算机

量子密码是基于量子理论的通讯技术,是一种让通讯自己不可窃听的技术,也能够理解为是一种利用光子的量子特性来实现通讯的方法。最先的量子密码中,利用了两个事实:
1. 从原理上说,没法准确测出光子的偏振方向

根据这一事实,可让窃听者获得的内容变得不正确。复制代码

2. 测量行为自己会致使光子的状态发送改变

根据这一事实,接收者能够判断出通讯是否被窃听。复制代码

量子计算机则有着超强的计算能力。若是有了量子计算机,那现有的全部密码都可以瞬间被暴力破解。根据量子理论,粒子可同时具备多种状态。若是使用具备多种状态的粒子进行计算,则能够同时完成多种状态的计算。若是用1个粒子可以计算0和1两种状态,那么用128个这样的粒子就能够同时计算2^128中状态。换句话说,就是一台超级并行计算机。

若是量子密码比量子计算机先进入实用领域,则可使用量子密码来实现一次性密码本,从而产生完美的密码技术。因为一次性密码本在原理上是没法破译的,所以即便用量子计算机也没法破译量子密码。然而,若是量子计算机比量子密码先进入实用领域,则实用目前的密码技术所产生的密文将会所有被破译。

只有完美的密码,没有完美的人

就算量子密码进入实用领域,也不能实现完美的安全。由于在安全问题中,密码技术可以覆盖的范围是很是有限的。在确保系统的总体安全方面,人是一个特别巨大的弱点。

为了配送对称密码的密钥,咱们须要使用公钥密码,而为了对公钥进行认证,咱们又须要认证机构的公钥。以此类推,无穷无尽,咱们必须在某个节点上找到一个公钥是本身可以彻底信任的,也就是必需要有一个信任的种子。

经过密码技术,咱们能够提升机密性,也可以让认证变得更加容易,可是这并不意味着咱们能够实现完美的机密性和完美的认证。

就算经过人的指纹、声纹、面容识别等生物识别认证也并非完美的认证。要进行生物识别认证,就必须在某个时间点上将生物信息转换为比特序列,而实际的认证则是经过转换后的比特序列来完成的。所以,若是这些比特序列被窃取,就会和钥匙被偷产生相同的后果。

另外,“防护必须完美无缺,攻击只需突破一点”。为了保卫系统安全,咱们必须应对各类可能的攻击,并且这种防护必须24小时连续工做。另外一方面,要攻击一个系统,则只要找到一种有效的攻击方法,并且只需利用防护方一瞬间的破绽就能够完成了。

写在最后

其实,在实际应用中,安全问题所涉及的技术,远比这本书里所讲到的密码技术多得多,也复杂得多。例如,App的加壳保护、OAuth认证等。在实际的应用中,还须要考虑更多,好比,安全性和性能之间须要平衡。虽然,懂得了这些密码技术,并不意味着就能设计出很是安全的系统。可是,若是不懂这些密码技术,那就更难以设计出安全的系统。


扫描如下二维码便可关注订阅号。

相关文章
相关标签/搜索