目录
(6) Alice用Bob发过来的数计算A次方并求mod P
(7) Bob用Alice发过来的数计算B次方并求mod P
小测验 1 的答案:Diffie-Hellman 密钥交换与中间人攻击 (11.5.5 节)
十一章
11.1 本章学习的内容
在密码技术中,密钥扮演着十分重要的角色。如果窃听者能够获得用于解密的密钥,则密文的机密性就无法得到保证;如果攻击者能够获得用于数字签名的私钥,就可以发动伪装攻击。
在之前的章节中我们多多少少已经接触了一些关于密钥的知识,本章我们将对下列知识点进行整理。
⚪什么是密钥
⚪各种不同的
⚪密钥密钥的管理
在此基础上,我们还将学习下列关于密钥的知识。
⚪Diffie-Hellman 密钥交换
⚪基于口令的密码(PBE)
⚪如何生成安全的口令
11.2 什么是密钥
11.2.1 密钥就是一个巨大的数字
在使用对称密码、公钥密码、消息认证码、数字签名等密码技术使用,都需要一个称为密钥(key)的巨大数字。然而,数字本身的大小并不重要,重要的是密钥空间的大小,也就是可能出现的密钥的总数量,因为密钥空间越大,进行暴力破解就越困难。密钥空间的大小是由密钥长度决定的。
为了让大家对密钥有一个直观的认识,我们来列举一些各种长度的密钥。
DES 的密钥
对称密码DES的密钥的实质长度为56比特(7字节)。
例如,一个 DES 密钥用二进制可以表示为:
01010001 11101100 01001011 00010010 00111101 01000010 000000111
用十六进制则可以表示为:
51 EC 4B 12 3D 42 03
而用十进制则可以表示为:
2305928028626269955
在下面的讲解中,我们将统一使用十六进制来表示。
三重 DES 的密钥
在对称密码三重 DES 中,包括使用两个 DES 密钥的 DES-EDE2 和使用三个 DES 密钥的DES-EDE3 两种方式。
DES-EDE2的密钥的实质长度为112比特(14字节),比如下面这个数字:
51 EC 4B 12 3D 42 03 30 04 D8 98 95 93 3F
DES-EDE3 的密钥的实质长度为168 比特(21 字节),比如下面这个数字:
51 EC 4B 12 3D 42 03 30 04 D8 98 95 93 3F 24 9F 61 2A 2F D9 96
AES 的密钥
对称密码AES的密钥长度可以从128, 192和256比特中进行选择,当密钥长度为256比特时,其长度如下面这个数字:51 EC 4B 12 3D 42 03 30 04 D8 98 95 93 3F 24 9F 61 2A 2F D9 96 B9 42 DC FD A0 AE F4 5D 60 51 F1
11.2.2 密钥与明文是等价的
正如上一节中所提到的,密钥仅仅是一个比特序列(字节序列),但它所具有的价值却超乎我们的想象。下面我们以对称密码的密钥为例,来思考一下密钥的价值。
假设Alice使用对称密码和密钥对明文进行了加密。Alice之所以要加密明文是因为她需要保密,而将明文转化为密文就可以保密了,因为即便密文被窃听者 Eve截获,Eve也无法得知明文的内容。然而,如果密钥落入 Eve手里会怎样呢? Eve可以用密钥将密文转化为明文,也就能够知道明文的内容了。
结果,对于窃听密文的 Eve 来说,得到密钥和得到明文是等价的。换言之,密钥和明文是等价的。假设明文具有100万元的价值,那么用来加密这段明文的密钥也就具有100万元的价值;如果明文值 1 亿元,密钥就也值 1亿元;如果明文的内容是生死攸关的,那么密钥也同样是生死攸关的。
11.2.3 密码算法与密钥
本书中反复提到,依靠隐藏密码算法本身的设计来确保信息的机密性是非常危险的。如果需要一个高强度的密码算法,不应该自行开发,而是应该使用一个经过全世界密码学家共同验证的密码算法。
信息的机密性不应该依赖于密码算法本身,而是应该依赖于妥善保管的密钥。这是密码世界的常识之一。
11.3各种不同的密钥
我们所说的密钥其实分为很多种类,下面我们来整理一下。
11.3.1 对称密码的密钥与公钥密码的密钥
在对称密码中,加密和解密使用同一个密钥。由于发送者和接收者之间需要共享密钥,因此对称密码又称为共享密钥密码。对称密码中所使用的密钥必须对发送者和接收者以外的人保密,否则第三方就能够解密密文了(图11-1)。 在公钥密码中,加密和解密使用的是不同的密钥。用于加密的密钥称为公钥,顾名思义它是可以被公开的;用于解密的密钥称为私钥,只有需要进行解密的接收者才持有私钥,私钥也称为秘密密钥。相对应的公钥和私钥之间具有深刻的数学关系,因此也称为密钥对(图11-2)。
11.3.2 消息认证码的密钥与数字签名的密钥
在消息认证码中,发送者和接收者使用共享的密钥来进行认证。消息认证码只能由持有合法密钥的人计算出来。将消息认证码附加在通信报文后面,就可以识别通信内容是否被篡改或伪装。由于“持有合法的密钥”就是发送者和接收者合法身份的证明,因此消息认证码的密钥必须对发送者和接收者以外的人保密,否则就会产生篡改和伪装的风险(图11-3)。 在数字签名中,签名的生成和验证使用不同的密钥。只有持有私钥的本人才能够生成签名,但由于验证签名使用的是公钥,因此任何人都能够验证签名(图 11-4)。
11.3.3 用于确保机密性的密钥与用于认证的密钥
对称密码和公钥密码的密钥都是用于确保机密性的密钥。如果不知道用于解密的合法密钥,就无法得知明文的内容。
相对地,消息认证码和数字签名所使用的密钥,则是用于认证的密钥。如果不知道合法的密钥,就无法篡改数据,也无法伪装本人的身份。
11.3.4 会话密钥与主密钥
刚刚我们关注的是密钥的用途,下面我们来关注一下密钥被使用的次数。
当我们访问以https://开头的网页时, Web服务器和浏览器之间会进行基于SSL/TLS的加密通信。在这样的通信中所使用的密钥是仅限于本次通信的一次性密钥,下次通信时就不能使用了。像这样每次通信只能使用一次的密钥称为会话密钥(session key)。
只能一次性使用的密钥有哪些好处呢?由于会话密钥只在本次通信中有效,万一窃听者获取了本次通信的会话密钥,也只能破译本次通信的内容。由于在下次通信中会使用新的密钥,因此其他通信的机密性不会受到破坏。
虽然每次通信都会更换会话密钥,但如果用来生成密钥的伪随机数生成器品质不好,窃听者就有可能预测出下次生成的会话密钥,这样就会产生通信内容被破译的风险。相对于每次通信都更换的会话密钥,一直被重复使用的密钥称为主密钥(master key)。
11.3.5 用于加密内容的密钥与用于加密密钥的密钥
下面我们来关注一下使用密钥加密的对象。
一般来说,加密的对象是用户直接使用的信息(内容),这样的情况下所使用的密钥称为CEK ( Contents Encrypting Key,内容加密密钥);相对地,用于加密密钥的密钥则称为 KEK(Key Encrypting Key, 密钥加密密钥)。图 11-5 中展示了 CEK 和 KEK 的一种用法。 将密钥进行加密好像有点奇怪,但通过像图 11-5 中这样的两段式方法,可以减少需要保管的密钥数量。
在很多情况下,之前提到的会话密钥都是被作为 CEK 使用的,而主密钥则是被作为 KEK使用的。后面提到的“保存密钥” (11.4.4节)以及“基于口令的密码”(11.6.1节)中也会出现KEK 密钥。
11.4 密钥的管理
11.4.1 生成密钥
用随机数生成密钥生成密钥的最好方法就是使用随机数,因为密钥需要具备不易被他人推测的性质。在可能的情况下最好使用能够生成密码学上的随机数的硬件设备,但一般我们都是使用伪随机数生成器这一专门为密码学用途设计的软件。
在生成密钥时,不能自己随便写出一些像“3F 23 52 28 E3 …”这样的数字。因为尽管你想生成的是随机的数字,但无论如何都无法避免人为的偏差,而这就会成为攻击者的目标。
在这里需要提醒会编程的读者注意。尽管生成伪随机数的算法有很多种,但密码学用途的伪随机数生成器必须是专门针对密码学用途而设计的。例如,有一些伪随机数生成器可以用于游戏和模拟算法,尽管这些伪随机数生成器所生成的数列看起来也是随机的,但只要不是专门为密码学用途设计的,就不能用来生成密钥,因为这些伪随机数生成器不具备不可预测性这一性质,关于这一点我们将在第 12章中详细探讨。
用口令生成密钥
有时我们也会使用人类可以记住的口令(password 或 passphrase)来生成密钥。passphrase指的是一种由多个单词组成的较长的 password,在本章中我们将两者统称为口令。
严格来说,我们很少直接用口令来作为密钥使用,一般都是将口令输入单向散列函数,然后将得到的散列值作为密钥使用。
在使用口令生成密钥时,为了防止字典攻击(11.6.4 节),需要在口令上面附加一串称为盐(salt)的随机数,然后再将其输入单向散列函数。这种方法称为“基于口令的密码”(Password Based Encryption, PBE),关于 PBE 我们稍后将详细介绍。
11.4.2 配送密钥
在使用对称密码时,如何在发送者和接收者之间共享密钥是一个重要的问题(即密钥配送问题)。在第5章中我们已经举例进行了介绍,要解决密钥配送问题,可以采用事先共享密钥、使用密钥分配中心、使用公钥密码等方法。除上述方法之外,还有一种解决密钥配送问题的方法称为 Diffie-Hellman 密钥交换,我们将稍后介绍。
11.4.3 更新密钥
有一种提高通信机密性的技术被称为密钥更新(key updating),这种方法就是在使用共享密钥进行通信的过程中,定期(例如每发送1000个字)改变密钥。当然,发送者和接收者必须同时用同样的方法来改变密钥才行。
在更新密钥时,发送者和接收者使用单向散列函数计算当前密钥的散列值,并将这个散列值用作新的密钥。简单说,就是用当前密钥的散列值作为下一个密钥。
进行密钥更新有哪些好处呢?我们假设在通信过程中的某个时间点上,密钥被窃听者获取了,那么窃听者就可以用这个密钥将之后的通信内容全部解密。但是,窃听者却无法解密更新密钥这个时间点之前的通信内容,因为这需要用单向散列函数的输出(即当前密钥)反算出单向散列函数的输入(即上一个密钥)。由于单向散列函数具有单向性,因此就保证了这样的反算是非常困难的。
这种防止破译过去的通信内容的机制,称为后向安全(backward security)。
11.4.4 保存密钥
由于会话密钥在通信过程中仅限使用一次,因此我们不需要保存这种密钥。然而,当密钥需要重复使用时,就必须要考虑保存密钥的问题了。
人类无法记住密钥
首先我们必须要理解一个重要的事实,那就是人类是无法记住具有实用长度的密钥的。例如,像下面这样一个AES的128比特密钥,一般人是很难记住的。
51 EC 4B 12 зD 42 03 30 04 D8 98 95 93 3F 24 9F
就算咬咬牙勉强记住了,也只不过是记住了一个密钥而已。但如果要自如地记住多个密钥并且保证不忘记,实际上是不可能做到的。
对密钥进行加密的意义
我们无法记住密钥,既然不能将密钥保存在自己的头脑中,那么就必须保存在其他某个地方。
于是我们现在就面临了一个巨大的困难。为了保证机密性,我们将文件进行了加密,而解密用的密钥就相当于保证文件机密性的钥匙。然而,将密钥和密文存放在同一台计算机中是非常愚蠢的。如果主动攻击者Mallory 能够访问保存密文的计算机,那么Mallory就很有可能同时获取到密文和解密用的密钥。
我们记不住密钥,但如果将密钥保存下来又可能会被窃取。这真是一个头疼的问题。这个问题很难得到彻底解决,但我们可以考虑一些合理的解决方法。
其中一种方法是,将密钥保存成文件,并将这个文件保存在保险柜等安全的地方。在这个场景中,我们是通过保险柜等其他装置来确保密钥的机密性的。
但是放在保险柜里的话,出门在外时就无法使用了。这种情况下,出门时就需要随身携带密钥。而如果将密钥放在存储卡里随身携带的话,就会产生存储卡丢失、被盗等风险。
万一密钥被盗,为了能够让攻击者花更多的时间才能真正使用这个密钥,我们可以使用将密钥加密后保存的方法。当然,要将密钥加密,必然需要另一个密钥。像这样用于加密密钥的密钥,一般称为 KEK。
既然加密密钥需要另一个密钥(KEK),那么另一个密钥(KEK)又要如何保存呢?我们好像又进入死循环了。
对密钥进行加密的方法虽然没有完全解决机密性的问题,但在现实中却是一个非常有效的方法,因为这样做可以减少需要保管的密钥数量。
举个例子,假设计算机上有 100 万个文件,分别使用不同的密钥进行加密生成 100 万个密文,结果我们手上就产生了100 万个密钥,而要保管100万个密钥是很困难的。
于是,我们用一个密钥(KEK)将这100万个密钥进行加密,那么现在我们只要保管这一个KEK 就可以了。不过大家不要忘记,这一个 KEK 的价值相当于前面 100 万个密钥的价值的总和。
用1个密钥来代替多个密钥进行保管的方法,和认证机构的层级化非常相似。在后者中,我们不需要信任多个认证机构,而只需要信任一个根 CA 就可以了。同样地,我们也不需要确保多个密钥(CEK)的机密性,而只需要确保一个密钥(KEK)的机密性就可以了。
关于密钥的具体保存方法,我们将在11.6节中进行介绍。
11.4.5 作废密钥
密钥的作废和生成是同等重要的,这是因为密钥和明文是等价的。
为什么要作废密钥
我们来思考一下作废密钥的意义。
举个例子,假设 Alice向Bob发送了一封加密的邮件。Bob在解密之后阅读了邮件的内容,这时本次通信所使用的密钥对于Alice和 Bob来说就不再需要了。不再需要的密钥必须妥善删除,因为如果被窃听者 Eve获取,之前发送的加密邮件就会被解密。
如何作废密钥
如果密钥是计算机上的一个文件,那么仅仅删除这个文件是不足以删除密钥的,因为有一些技术能够让删除的文件“复活”。此外,很多情况下文件的内容还会残留在计算机的内存中,因此必须将这些痕迹完全抹去。简而言之,要完全删除密钥,不但要用到密码软件,还需要在设计计算机系统时对信息安全进行充分的考虑。
密钥丢了怎么办
如果包含密钥的文件被误删,或者保管密钥的笔记本电脑损坏了,会导致怎样的后果呢?
如果丢失了对称密码的共享密钥,就无法解密密文了。如果丢失了消息认证码的秘钥,就无法向通信对象证明自己的身份了。
公钥密码中,一般不太会发生丢失公钥的情况,因为公钥是完全公开的,很有可能在其他电脑上存在副本。
最大的问题是丢失了公钥密码的私钥。如果丢失了公钥密码的私钥,就无法解密用公钥密码加密的密文了。此外,如果丢失了数字签名的私钥,就无法生成数字签名了。
11.5 Diffie-Hellman密钥交换
本节中我们将介绍另一种解决密钥配送问题的方法——Diffie-Hellman密钥交换。
11.5.1什么是Diffie-Hellman密钥交换
Diffie-Hellman 密钥交换(Diffie-Hellman key exchange )是 1976 年由 Whitfield Diffie 和Martin Hellman共同发明的一种算法。使用这种算法,通信双方仅通过交换一些可以公开的信息就能够生成出共享的秘密数字,而这一秘密数字就可以被用作对称密码的密钥。IPsec中就使用了经过改良的Diffie-Hellman密钥交换。
虽然这种方法的名字叫“密钥交换”,但实际上双方并没有真正交换密钥,而是通过计算生成出了一个相同的共享秘钥。因此,这种方法也称为 Diffie-Hellman密钥协商(Diffie-Hellmankey agreement )。
11.5.2 Diffie-Hellman密钥交换的步骤
现在我们假设 Alice和 Bob 需要共享一个对称密码的密钥,然而双方之间的通信线路已经被窃听者Eve窃听了。这时, Alice和Bob可以通过以下方法进行Diffie-Hellman密钥交换,从而生成共享密钥(图 11-7)。
(1) Alice向Bob发送两个质数P和G
P必须是一个非常大的质数,而G则是一个和P相关的数,称为生成元(generator)。G可以是一个较小的数字。关于生成元的概念我们将稍后讲解。
P和G不需要保密,被窃听者Eve获取也没关系。
此外,P和 G 可以由 Alice 和 Bob 中的任意一方生成。
(2) Alice 生成一个随机数 A
A 是一个 1-P-2之间的整数。这个数是一个只有 Alice知道的秘密数字,没有必要告诉Bob,也不能让 Eve 知道。
(3) Bob 生成一个随机数 B
B 是一个 1~P-2之间的整数。这个数是一个只有 Bob 知道的秘密数字,没有必要告诉Alice,也不能让 Eve 知道。
(4) Alice将G mod P这个数发送给Bob
这个数让 Eve 知道也没关系。
(5) Bob将G mod P这个数发送给Alice
这个数让 Eve 知道也没关系。
(6) Alice用Bob发过来的数计算A次方并求mod P
这个数就是共享密钥。
Alice 计算的密钥=(G mod P) mod P
我们将上面的算式简化:
Alice 计算的密钥 = G^B×A mod P
= G^A ×B mod P
上面我们将mod P中的"G的B次方的A次方”改写成了"G的Ax B次方”
(7) Bob用Alice发过来的数计算B次方并求mod P
Bob计算的密钥= (G^A mod P)^B mod P
我们将上面的算式简化:
Bob 计算的密钥 = G^A ×B mod P
上面我们将mod P中的"G的A次方的B次方”改写成了"G的A×B次方"。于是,Alice和Bob就计算出了相等的共享密钥。
Alice 计算的密钥 = Bob 计算的密钥
11.5.3 Eve能计算出密钥吗
在步骤(1)~(7)中,双方交换的数字(即能够被窃听者 Eve 知道的数字)一共有 4 个:P、G、 G^A mod P和 G^B mod P。根据这 4个数字计算出 Alice和 Bob 的共享密钥(G^A ×B mod P)是非常困难的。
如果 Eve 能够知道 A 和 B 中的任意一个数,那么要计算 G^A ×B 就很容易了,然而仅仅根据上面4个数是很难求出 A 和 B的。
举个例子,我们能够根据 G^A mod P计算出 A 吗?G^A mod P中的 mod P 是这里的关键所在。如果仅仅是 G^A 的话,要计算出 A 并不难,然而根据 G^A mod P计算出 A 的有效算法到现在还没有出现,这个问题称为有限域((finite field)的离散对数问题。
而有限域的离散对数问题的复杂度正是支撑 Diffie-Hellman 密钥交换算法的基础。
11.5.4 生成元的意义
已知P为质数,让我们来想象一下mod P的时钟运算(5.5节)。假设P为13,则mod P的时钟运算中所使用的时钟就是以下13个数字画成的圆形时钟。
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
然后我们来列一张0~12各元素的乘方表(表11-1)。
在上表中,请大家注意看G等于 2 的那一行。
我们可以发现2^1到2^12的值(共12个)全都不一样。也就是说,2 的乘方结果中出现了1 到12的全部整数。由于2 具备上述性质,因此称为13的生成元。同样地,6、7和11 也是生成元。
也就是说,P的生成元的乘方结果与1~P-1中的数字是一一对应的。正是因为具有这样一一对应的关系,Alice才能够从1-P-2的范围中随机选择一个数字(之所以不能选择P-1,是因为 GP-1 mod P的值一定是等于 1 的 )。当然,从数学上看我们还必须证明对于任意质数 P都一定存在生成元G,但证明的过程在这里就不再阐述了。
小测验 1 Diffie-Hellman 密钥交换与中间人攻击 (答案见 11.9 节)
学习了'Diffie-Hellman密钥交换的知识后, Alice产生了下面的疑问。如果主动攻击者 Mallory 混入进行 Diffie-Hellman 密钥交换的两个人中间,能否进行伪装攻击(中间人攻击)呢?
请你解答 Alice的疑问吧。
11.5.6 椭圆曲线Diffie-Hellman密钥交换
Diffie-Hellman 密钥交换是利用“离散对数问题”的复杂度来实现密钥的安全交换的,如果将“离散对数问题”改为“椭圆曲线上的离散对数问题”,这样的算法就称为椭圆曲线DiffieHellman 密钥交换。
椭圆曲线 Diffie-Hellman 密钥交换在总体流程上是不变的,只是所利用的数学问题不同而已。椭圆曲线 Diffie-Hellman 密钥交换能够用较短的密钥长度实现较高的安全性,详情请参见附录 1 中的介绍。
11.6 基于口令的密码(PBE)
11.6.1 什么是基于口令的密码
顾名思义,基于口令的密码( Password Based Encryption, PBE)就是一种根据口令生成密钥并用该密钥进行加密的方法。其中加密和解密使用同一个密钥。
PBE有很多种实现方法。例如RFC 2898 ( PKCS #5 )和RFC 7292 ( PKCS #12 )等规范中所描述的PBE就通过Java的javax.crypto包等进行了实现。此外,在通过密码软件PGP保存密钥时,也会使用 PBE。本节中,我们不会介绍具体的规范,而是从一般的方法的角度来介绍PBE。
PBE 的意义可以按照下面的逻辑来理解。
想确保重要消息的机密性。
⬇
将消息直接保存在磁盘上的话,可能会被别人看到。
⬇
用密钥(CEK)对消息进行加密吧。
⬇
但是这次又需要确保密钥(CEK)的机密性了。
⬇
将密钥(CEK)直接保存在磁盘上好像很危险。
⬇
用另一个密钥(KEK)对密钥进行加密(CEK)吧。
⬇
等等!这次又需要确保密钥(KEK)的机密性了。进入死循环了。
⬇
既然如此,那就用口令来生成密钥(KEK)吧。
⬇
但只用口令容易遭到字典攻击。
⬇
那么就用口令和盐共同生成密钥(KEK)吧。
⬇
盐可以和加密后的密钥(CEK)一起保存在磁盘上,而密钥(KEK)可以直接丢弃。
⬇
口令就记在自己的脑子里吧。
11.6.2 PBE 加密
PBE的加密过程如图 11-8 所示。
PBE 加密包括下列 3个步骤:
(1)生成 KEK;(2)生成会话密钥并加密;(3)加密消息。
(1)生成KEK
首先,伪随机数生成器会生成一个被称为盐的随机数。将盐和 Alice输入的口令一起输入单向散列函数,得到的散列值就是用来加密密钥的密钥(KEK)。
正如在饭菜上撒盐会改变饭菜的味道一样,在口令上加上盐就会改变所生成的KEK值。盐是一种用于防御字典攻击(稍后讲解)的机制。
(2)生成会话密钥并加密(CEK)。
接下来,我们使用伪随机数生成器生成会话密钥。会话密钥是用来加密消息的密钥(CEK)。
会话密钥需要用刚才步骤(1)中生成的 KEK 进行加密,并和盐一起保存在安全的地方。会话密钥加密之后, KEK就会被丢弃,因为KEK没有必要保存下来,只要通过盐和口令就可以重建 KEK。
(3) 加密消息
最后,我们用步骤(2)中生成的会话密钥对消息进行加密。
PBE加密后所产生的输出包括下列3种。
⚪盐
⚪用 KEK 加密的会话密钥
⚪用会话密钥加密的消息
其中“盐”和“用KEK加密的会话密钥”需要保存在安全的地方。
11.6.3 PBE解密PBE 的解密
过程如图 11-9 所示。
PBE 解密包括下列 3个步骤。
(1)重建KEK ; (2)解密会话密钥; (3)解密消息。
(1) 重建 KEK
首先我们将之前保存下来的盐,和 Alice 输入的口令一起输入单向散列函数。这个计算过程和生成 KEK 时的计算过程是一样的,因此所得到的散列值就是 KEK。
(2)解密会话密钥
然后,我们获取之前保存下来的“用 KEK加密的会话密钥”,用步骤(1) 中恢复的KEK 进行解密。这一步我们可以得到会话密钥。
(3) 解密消息
最后,我们用步骤(2)中重建的会话密钥对加密的消息进行解密。将上述解密过程与图 11-8 中“PBE 加密”的过程对比一下就会发现,在 PBE 加密过程中使用了两次伪随机数生成器,而在PBE解密过程中却一次都没有使用。
11.6.4 盐的作用
盐是由伪随机数生成器生成的随机数,在生成密钥(KEK)时会和口令一起被输入单向散列函数。
密钥(KEK)是根据秘密的口令生成的,加盐好像没有什么意义,那么盐到底起什么作用呢?
盐是用来防御字典攻击的。字典攻击是一种事先进行计算并准备好候选密钥列表的方法。
我们假设在生成KEK的时候没有加盐。那么主动攻击者Mallory就可以根据字典数据事先生成大量的候选 KEK。
在这里,事先是很重要的一点。这意味着Mallory可以在窃取到加密的会话密钥之前,就准备好了大量的候选 KEK。当 Mallory窃取加密的会话密钥后,就需要尝试将它解密,这时只要利用事先生成的候选 KEK,就能够大幅缩短尝试的时间,这就是字典攻击(dictionaryattack)。
如果在生成 KEK 时加盐,则盐的长度越大,候选 KEK 的数量也会随之增大,事先生成候选 KEK 就会变得非常困难。只要 Mallory 还没有得到盐,就无法生成候选 KEK。这是因为加盐之后,候选KEK 的数量会变得非常巨大(图 11-10)。
11.6.5 口令的作用
大家应该已经理解了盐在基于口令的密码(PBE)中所发挥的作用。下面我们来说说口令。
请大家回忆一下我们之前提到的一个事实:具有充足长度的密钥是无法用人脑记忆的(11.4.4 节)。口令也是一样,我们也无法记住具有充足比特数的口令。
在 PBE中,我们通过口令生成密钥(KEK),再用这个密钥来加密会话密钥(CEK)。由于通过口令生成的密钥(KEK)强度不如由伪随机数生成器生成的会话密钥(CEK),这就好像是将一个牢固的保险柜的钥匙放在了一个不怎么牢固的保险柜中保管,因此在使用基于口令的密码(PBE)时,需要将盐和加密后的CEK通过物理方式进行保护。例如可以将盐和加密后的CEK 保存到存储卡中随身携带。
11.6.6 通过拉伸来改良 PBE
在生成KEK时,通过多次使用单向散列函数就可以提高安全性。例如,如果我们将盐和口令先输入单向散列函数,然后将得到的散列值再次输入单向散列函数,将得到的散列值又再次输入单向散列函数…像这样将经过1000次散列函数所得到的散列值作为KEK来使用,是一个不错的方法。
对于用户来说,执行1000次散列函数并不会带来多大的负担。因为和用户输入一次口令所花费的时间相比,执行1000次散列函数所需的时间可以忽略不计。然而,对于主动攻击者Mallory来说,这可是一个很大的负担。因为为了找出正确的KEK, Mallory必须用大量的口令进行尝试。
像这样将单向散列函数进行多次迭代的方法称为拉伸(stretching)。
11.7 如何生成安全的口令
到这里, PBE的相关知识就讲完了,下面我们来就口令的话题进行一些更深入的思考。
当我们在计算机上登录时,需要输入口令。通过输入口令,我们可以证明自己拥有登录这台计算机的权利。
在将用PBE加密的文章进行解密时,我们也需要输入口令。这个过程也是通过输入口令来证明自己拥有解密该文章的权利。
口令是非常重要的,但是要生成安全的口令却是非常难的。下面我们来介绍一些生成安全的口令的小技巧。
⚪使用只有自己才能知道的信息
⚪将多个不同的口令分开使用
⚪有效利用笔记
⚪理解口令的局限性
⚪使用口令生成和管理工具
11.7.1 使用只有自己才能知道的信息
在生成口令时,使用只有自己才能知道的信息是一个大原则。因为口令不能够被别人推测出来,因此使用只有自己才能知道的信息是理所当然的。然而,在实际生成口令的时候,人们却很容易忘记这一原则。
让我们来具体讲一讲。
不要使用对自己重要的事物的名字
由于口令非常重要,很多人往往会使用对自己重要的事物的名字。例如,自己恋人的名字、配偶的名字、孩子的名字、宠物的名字、偶像的名字、车的名字、品牌的名字……。然而,对自己重要的事物的名字反而是容易被别人推测出来的信息,因此我们不应该在口令中使用这些名字。
不要使用关于自己的信息
这一点其实不必多说,不要在口令中使用像自己的名字、自己的登录用户名、地址、员工号码等和自己相关的信息。不要使用别人见过的信息不要使用一些别人可能看到过的信息作为口令,例如名言、有名的引文、字典的例句、网上看到的话、键盘上的字母顺序(qwerty、asdfghjkl)、彩虹的颜色、行星的名字、星座、月份、星期等。
这样一看,只有自己才知道的信息真的是非常有限的,因此生成一个安全的密码其实并不容易。
11.7.2 将多个不同的口令分开使用
不要将同一个口令重复用于各种不同的用途,而是应该根据信息的价值区分使用不同的口令。例如,用来在网站上阅读新闻的口令,和用来加密包含1000个客户信息的重要文件的口令显然不能用同一个。
在区分使用口令时,不能仅仅改变口令的一部分。比如说下面这样的做法就是不可以的。
登录公司计算机的口令 tUniJw1
登录家里计算机的口令 tUniJw2
网上购物用的口令 tUniJw3
用于邮件数字签名的口令 tUniJw4
这样的话,只要破译其中一个口令,其他的口令就很容易被推测出来。
11.7.3 有效利用笔记
不可以将口令写在便签上然后贴在计算机的屏幕上,特别是在人来人往的办公室里更是严禁这种行为。
不过,有效利用笔记也并不是坏事。与其以好记为理由设置一个简单的口令,还不如用伪随机数生成器生成一个随机的字符串作为口令,然后将口令记下来保存在安全的地方。换言之,应该将笔记与物理的钥匙同等对待。仅将口令的一部分写下来的方法也是非常有效的。
11.7.4 理解口令的局限性
口令是有局限性的。为了说明起来更简单,我们假设口令只能由8个字符的英文字母和数字组成。英文字母和数字一共有 62 个,即:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
因此,8个英文字母和数字的组合的可能性为:
62× 62× 62 x 62 x 62 × 62× 62 ×62
=62^8
= 218340105584896
也就是大约 218 万亿种。这个数字虽然不小,但实际上只不过相当于一个长度为 48比特的密钥而已。这个长度的密钥是可以通过暴力破解的。如果攻击者的计算机每秒可以生成并尝试1亿个口令,则只需要25天就可以遍历所有的口令了。
11.7.5使用口令生成和管理工具
我们刚才介绍了一些生成安全口令的小技巧,可能很多读者会感慨生成口令原来这么麻烦。实际上,现如今靠人自己来生成和管理口令可以说是非常困难的。
如今,我们要使用的网站非常多,其中大部分都需要使用用户名和口令来登录。为了解决人类难以直接管理口令这个现实问题,就需要一些能够帮助我们生成和管理口令的工具。
这些工具通过随机数来生成难以推测的口令,并能够与浏览器联动在网站上自动输入相应的口令。
不过,我们也必须提防这些工具擅自盗用用户的口令,也就是说,这些工具及其开发者是否“可信”是非常重要的。
11.8 本章小结
本章中我们探讨了密码技术中所使用的密钥。
自己的房子再宝贵,也不能在出门的时候连房子一起带走。因此我们会给房子上锁,然后把钥匙带走。锁保卫房子的安全,而我们则需要保卫钥匙的安全。密码中的密钥也是一样的。密码算法保卫明文的安全,而我们则需要保卫密钥的安全。
密钥就是密码技术的钥匙。密钥这样一个很短的比特序列可以确保重要信息的机密性,还可以证明你的身份。
下一章中,我们将介绍在生成密钥时需要用到的伪随机数生成器。
小测验 2 密钥的基础知识 (答案见 11.9 节)
下列说法中,请在正确的旁边画⚪,错误的旁边画×。
(1)由于密钥只是随机的比特序列,因此被别人知道了也没关系。
(2)私钥是可以公开的。
(3) 在 Diffie-Hellman 密钥交换中,双方可以通过交换一些可以公开的信息生成出共享密钥。
(4)用来加密重要文件的口令,可以使用“妈妈的娘家姓”这种不容易忘记的信息。
11.9 小测验的答案
小测验 1 的答案:Diffie-Hellman 密钥交换与中间人攻击 (11.5.5 节)
针对 Diffie-Hellman 密钥交换是可以发动中间人攻击的。
假设Mallory现在位于Alice和Bob中间。当Alice给 Bob发送G mod P时, Mallory可以拦截这条消息,然后伪装成Alice向Bob发送G* mod P (这里X是Mallory 随机生成的秘密数字)。
同样地,当Bob向Alice发送Gmod P时, Mallory 再伪装成Bob向Alice发送G mod P(Y也是 Mallory 随机生成的秘密数字)。
此后,当Alice和Bob使用共享密钥进行对称密码通信时, Mallory就可以解密所有的通信内容。Alice和Bob以为他们彼此在进行密码通信,但实际上位于中间的Mallory才是真正的通信对象,他可以对Alice伪装成Bob,对Bob伪装成Alice。
针对这样的攻击,我们可以像公钥密码通信一样使用数字签名、证书等方法来应对。在IPsec 中使用的 Diffie-Hellman 密钥交换,就针对中间人攻击进行了改良和扩展。
小测验 2 的答案:密钥的基础知识 (11.8节)
(1) 由于密钥只是随机的比特序列,因此被别人知道了也没关系。
× 答案:密钥虽然是随机的比特序列,但是它和它所保护的信息具有相同的价值,因此不能随便告诉别人。
(2)私钥是可以公开的。
× 答案:私钥是不可以公开的,而公钥才是可以公开的。
⚪ (3) 在 Diffie-Hellman 密钥交换中,双方可以通过交换一些可以公开的信息生成出共享密钥。
(4)对于用来加密重要文件的口令,可以使用“妈妈的娘家姓”这种不容易忘记的信息。
× 答案:“妈妈的娘家姓”的确不容易忘记,但是也是很容易被别人推测出来的信息,因此用在口令上是不合适的。