【2021-11-08 更新】【梳理】简明操作系统原理 第二十章 加密(docx)

配套教材:
Operating Systems: Three Easy Pieces Remzi H. Arpaci-Dusseau Andrea C. Arpaci-Dusseau Peter Reiher
参考书目:
1、计算机操作系统(第4版) 汤小丹 梁红兵 哲凤屏 汤子瀛 编著 西安电子科技大学出版社

在线阅读:
http://pages.cs.wisc.edu/~remzi/OSTEP/
University of Wisconsin Madison 教授 Remzi Arpaci-Dusseau 认为课本应该是免费的
————————————————————————————————————————
这是专业必修课《操作系统原理》的复习指引。
需要掌握的概念在文档中以蓝色标识,并用可读性更好的字体显示 Linux 命令和代码。代码部分语法高亮。
文档下载地址:
链接:https://pan.baidu.com/s/11alVHqKWYI-a0KFgd00UbA
提取码:0000

二十 加密

操作系统只在受限的领域内具有相当大的控制权。它既无法控制其它机器上发生的一切,也无法控制当使用自身以外的机制访问运行自己的硬件时,会发生什么。如何令操作系统保护不由它控制的资源的访问呢?假设我们将要丢失数据,或者敌人正尽力去篡改数据。我们采取措施,令这些情况不引发问题。关键的一点观察:如果敌方无法理解获取到的数据的形式,我们的秘密就安全了。既然攻击者连明白拿到的东西都不行,很可能也就没能力篡改它们——至少不能通过可控的方式。
我们使用的核心技术是:密码学(cryptography)。密码学包含一系列技术集合,用于通过可控的方式,转换数据为另一种可预测的形式。如果正确发挥其作用,攻击人员就无法通过考察保护形式的数据来确定原始数据。当然,对于我们自己,还必须同时确保能够正确还原数据为原始形式。正确使用密码学,不但能够防止数据遭到篡改,还可以得知是谁尝试破坏数据。
但这并不容易。许多使用方式都需要很大的算力。所以,要对使用方法做出适当选择,并谨慎实现与集成至系统中。选定了加密的正确使用方式,可以极大增加安全性。否则,不但可能一点帮助都没有,或许还会造成额外损害。
关于密码学的书籍有很多,在这里我们只用一章进行讲解。即便如此,还是可以讨论许多有用的东西。那些复杂的密码学问题在这里基本都可以忽略,毕竟我们并不是要全都成为密码学家。我们只是要成为技术的使用者,依赖内行的专家们提供的、可以不完全明白原理就使用的工具。相对地,我们当中只有少数人明白计算机硬件工作的深层细节,但我们仍能成功使用计算机,因为能接触到良好的界面(接口)。聪明人们在设计硬件时,已经花了非常多的心思考虑我们了。类似地,加密技术也提供了强大的接口和良定义的行为。
即便如此,加密技术也不是魔法棒。只是为了正确使用它,也依然需要有许多应当明白的知识,尤其是在使用操作系统的过程中。

密码学的基本思想是:取一段数据,使用一个算法(常称为加密算法,cipher),算法通常由第二段信息(称为密钥,key)增强,将数据转换为不同的形式。新形式不应该看起来与原有的形式有相像。典型地,我们也希望能运行另一种算法(算法也由另一段信息增强),将数据恢复原来的形式。
形式化地说,如果数据记为P(通常称为明文,plaintext),密钥为K,加密(encryption)算法E(),加密结果为C:它是P的另一种形式。则密文(ciphertext)

C=E(P,K)
Caesar密码(Caesar cipher)是最古老、最简单、最广为人知的一种加密技术。它将明文中的所有字母都在字母表上向后或向前移动一个固定的步数,通常被作为更复杂的加密中的一个步骤。Caesar密码最早由罗马共和国(Roman Republic)末期的Gaius Iulius Caesar(盖乌斯·尤利乌斯·恺撒)用于在军队中传递加密信息。现在已经无法弄清凯撒密码在当时有多大的效果,但是有理由相信它是安全的。因为凯撒的大部分敌人都目不识丁,而其余的则可能将这些消息当作是某个未知的外语。即使有敌人获取了凯撒的加密信息,根据现有的记载,当时也没有任何技术能够解决这一最基本、最简单的替换密码。
反变换算法接收密文C,使用解密(decryption)算法D()和密钥K重新得到明文
P=D(C,K)
为了加密过程能够有用,使信息能以加密形式成功传递,首先,加密过程必须是确定性的。即:对于一段特定的明文P,使用相同的加密算法E()和密钥K,必须总是得到相同的密文C。同样地,对一段特定的密文C,使用相同的解密算法D()和密钥K,必须总是得到相同的明文P。许多情况下,加密算法与解密算法相同,但这不是必须的。此外,还要求在密钥K未知的条件下,想从密文C得到明文P极为困难。能够实现严格的不可能固然好,但如果只是达到破译出明文在计算上不可行(computationally infeasible),通常也能满足要求了。如果能这样做,我们大可直接将密文C亮给最庞大的敌人,即便是世界上最聪明的人员,也无法从密文C得到明文P。

当然……很明显,这里就是理论的论文和纷乱的现实开始碰撞的地方了。我们只能被保证,在敌方不知道加密算法D()和密钥K时,能够确保秘密性(secrecy)。如果敌人获得了加密算法D()和密钥K,就能输入密文C得到明文P。
实际上,我们无法让加密算法E()和解密算法D()不被获取。
加密和解密算法做出来以后,是要给人用的,而且一般要大规模应用。大量事实证明,无论使用专门的硬件实现还是软件实现,都无法阻挡其他人(哪怕并不是数学或密码学等领域的重量级人物)将算法破解出来。也许有人会提出,由警察乃至部队来强制保证加密与解密算法不被公开。但是,在安全的战线上,从来不缺间谍。收买、威胁、绑架掌握了密码或加密或解密算法的人员,甚至可能要比直接拿到写有加密或解密算法的文件,或者截获运行了相关算法的硬件或软件去进行破解,来得更为方便。
必须指出,加密算法的“安全性”没有严格的、明确的数学定义。目前,考察加密算法的安全性的唯一标准就是:这个算法是否经得住大量的、多种多样的破解尝试。一个加密算法安全不安全,一个专家说了不算,十多个专家说了也不算;就算全世界的密码学家都说它安全,但在大规模投入使用的过程中,碰巧偶然发现了一个不小的漏洞,他们说的也还是不算。
声称一种密码算法是安全的,必须要让大家相信,这样的声明才有意义。信任来自哪里?可以是数字证书的专门管理机构,也可以是软件厂商,专业的研究人员,仅凭兴趣就来参与研究的白帽子(white hat),还可以是大量完全不懂密码学的非专业人员。对加密算法遮遮掩掩、步步严控,如何让大家相信算法是安全的,并敢于充分投入实际使用呢?假如你不敢把你的加密算法拿出来给大家看,但是我就敢,我把算法的细节都毫无保留地写成论文发布出来,甚至连实现的源代码都写了一份,让大家亲自尝试。我都公开成这样了,结果所有人都花了很久时间,也还是破不了这个算法。这不正说明了,你没有底气表明你的算法具有高安全性,而我就有底气向大家保证,我本人的加密算法的安全性才足够高吗?
目前,已经公开了许多在数学上能够表明其极难被破解的加密算法。它们都是基于绝对不可以违逆的数学规律。可以十分肯定,它们比任何人都可靠——全世界最顶级的大脑汇聚起来,绞尽脑汁,都难以将它们的安全性降低。
加解密算法的不公开,不能提高加密的可靠性。这是反常识的。密码学这个新兴领域有太多反常识的东西。例如,加密算法未知时,也可以构造出解密算法。假设某人意外获得了一些明文-密文对(比如,买通了单位的“内鬼”)。如果算法设计存在较多的漏洞,那么,根据这些明文与密文的对应关系,就可能猜出加密算法的数学性质;根据这些性质,就有机会给出一个解密算法。又例如,有的时候,重复使用相同的算法加密多次,或者混用不同的加密算法,反而会降低安全性。许多算法甚至还无法保证,安全性随着密钥长度的增加而增加。一些密钥的安全性还会比其它密钥弱,即便它们长度相同。
我们知道,要进行加密或解密,必须同时知道算法和密钥两个因素。与将算法保密起来相比,保密密钥容易得多。密钥暴露以后,只要及时更换,一般就可以马上恢复到密钥暴露之前的安全性。使用现在公开的那些公认的安全性足够高的加密手段,已经异常容易做到。而且,算法的细节可以在不经意间被泄露出去。保密的成本是很高的,对于没有必要保密的东西,就不应当投入人力物力对其保密。
密码学的复杂程度是难以想象的,即便是密码学的顶级专家们,胆敢声称某种新兴算法是安全的,也常常被打脸。因此,如果你或某个组织认定自己开发的密码系统至少要强于绝大多数公开的密码系统,那基本上就是严重高估自己的能力了。如果你或你所属的机构(你是顶级的密码学家之一吗?又或者,你所在的机构拥有大量的顶级密码学家吗?)只是到处去吹嘘自己做出来的神奇算法,密码学家们一般只是忽略,他们已经听得太多了。只是,如若你们把这个算法用于加密一些重要的内容,很不幸,这或许就会招致他们的注意。以他们的能力,很容易就会把算法给干烂。时常听说的相当多的加密算法,都是由世界顶级密码学家们创建的,它们中的很多也都被陆续发现了缺陷。将加解密算法公开,这些算法便有机会经历多得多的破解挑战(破解过程自然也是要全部公开的)。构造良好的加密算法极度困难。如果这些算法能更广泛地被研究,那么其安全漏洞就有可能更快被找出来,它被研究到何种程度也能及时知晓,其改进方案也就有机会更早被制定出来。而且,足够多的公开,有利于行业尽快建立新的保密相关的标准,促进需要使用密码的各个领域的发展。加密算法和破解过程的公开,早已成为密码学界的基本共识。
假如密码算法具备弱点,那么敌人就可以在不知道密钥K的条件下,提取出明文P来。因此,必须拥有良好的加密算法。这是很难做到的。毕竟,我们没法将世界级的密码学家给轻易搞来,开发新的加密算法。因此,我们不得不依赖已知的强密码算法。高级加密标准(advanced encryption standard,AES),它被谨慎而彻底地研究了,但它成功抵抗了几乎所有的攻击。虽然在一些对保密要求更高的领域,它的安全性有所降低——也就是说,破解需要的算力减少了;但总体而言,它的安全性依然很高。毕竟还没有将AES加密后的密文完全还原出来的先例。按目前人类已经掌握的算力,这是绝对无法做到的。
接下来这句话极度重要:密码学的益处完全依赖于密钥的保密性。把这句话读个几十遍,也大概率不会对你有害的。那些没有把这一课记在心里的不安全系统煞了风景。
好消息是,如果使用了强加密算法,并且保管好了密钥,那么你的加密很强大。你无需再担心其它事情了。坏消息是,在现实中,维持密钥的保密性并不容易。后续我们再讨论这一点。
攻击者假若修改了密文,也就是从C改成了C^',那么,使用指定的解密算法解密时,也就无法获得原来的明文P,而是另外一种明文P^'。当然,在算法足够良好的情形下,P^'是无法被预测出来的,除非知道密钥K。
即便P^'被搞出来了,它也极大概率只是一堆垃圾信息。如果我们要检测明文P变成了意义不明的P^',可以在加密之前将P做一次哈希,并将哈希值保存下来。解密以后,若哈希值发生变化,则应当判定信息遭到篡改。

假使有个人交给你一段数据:它用密钥K加密了,而且K只有你和你的伙伴Remzi知道。你自己当然也清楚:不是自己创建的密钥K。如果使用K能顺利解密,那只能是Remzi创建了K。于是,我们得以使用加密来验证身份。这种加密称为对称加密(symmetric cryptography)。AES就是一种对称加密标准。很长一段时间里,每个人都相信这是唯一可能的加密方式。但是,大家都错了。

为了验证加密信息的真实性,需要知道加密它的密钥。如果只是在意使用加密去验证身份,这就不方便了。意思是说,我们要把密钥告知任何可能需要验证我们的真实性的人员。假如我们是Microsoft,需要为每个购买了我们的软件的用户验证他们购买的软件是否为正版。我们不能只使用一个密钥,因为只要有一个人得知了这个密钥,他就可以冒充Microsoft了。换个方式,Microsoft为上亿用户中的每个都生成不同的密钥。但这就需要把每个唯一的密钥秘密地发送给每个用户,更不必说追踪这些密钥了。
密码学告诉我们,加密和解密允许使用不同的密钥。即

C=E(P,K_E )
P=D(C,K_D )
对Microsoft来说,生活变得容易多了。他们可以公开解密密钥K_D,用户们凭此检验软件是否为正版。例如,Microsoft可以使用K_E加密一个操作系统更新,然后发送给全部用户。每个用户都能使用K_D解密。如果解密后得到一个正确的软件更新,用户就能确定它由Microsoft创建。并没有其他人知道私钥,也就不可能是其他人创建的更新。
听起来很神奇,但实际上这有数学依据在撑腰。我们不讨论数学上的细节,只是你不得不相信这是很巧妙的。这种加密称为公钥加密(公开密钥加密,public key cryptography,PK),因为两个密钥中的一个可以广为公众所知,且仍然能够达到期望的加密效果。所有人都知道的密钥称为公钥(public key),只有持有者知道的密钥称为私钥(private key)。公钥加密是一种非对称加密(asymmetric encryption),因为加密和解密使用不同的密钥。
公钥避免了之前的加密形式面临的一个困难:需要安全地分发密钥。在公钥加密中,私钥由特定的一方创建并保密。它从不被分发给其他人。公钥必须被分发开来,但我们并不在意第三方获得了公钥,因为他们不能用公钥来签名信息。公钥分发比需要保密的密钥的分发更容易,即便这比听起来更难实现。
也可以使用解密密钥K_D加密,这时需要使用加密密钥K_E来解密。如果用于解密的密钥K_E是公开的,就无法再进行身份验证。所有人都可以使用K_D去加密,但只有K_E的所有者才能解密,这允许任何人提供公钥并发送加密信息给具有私钥的人员。因此,使用私钥加密能够进行真实性验证,使用公钥加密能够进行秘密通信。
若同时需要这两项功能,则需要两对不同的密钥对。设Alice想要使用公钥加密与伙伴Bob秘密通信,同时希望确保Bob可以确定消息来自Alice。且Alice和Bob都具有自己的公钥-私钥对。他们各自知道自己的私钥和对方的公钥。如果Alice使用她的私钥加密信息,她就能保证消息的真实性,因为Bob能使用她的公钥解密并确定只有Alice能创建此信息。但所有人都知道Alice的公钥,因此消息的秘密性也就没有了。然而,如果Alice将真实性验证后的信息再次使用Bob的公钥进行加密,那么只有Bob才能使用私钥解密并读取信息。于是,Bob一共需要解密2次,一次使用他自己的私钥,一次使用Alice的公钥。
事实上,这比你想象的消耗更大。公钥加密有一个缺点:相比传统的依赖单共享密钥(single shared key)的加密,它消耗的算力多得多。公钥加密需要几百倍于标准的对称加密的时间。因此,无法将其应用到一切事物上。
还有另一个重要的问题。Alice和Bob都互相知道对方的公钥。如何达到这样的事态?起先,Alice和Bob只知道各自的公钥。这个过程要小心,因为这之后,Bob将假定公钥加密后的信息的确由Alice创建。如果某些邪恶的聪明人,比如Eve,成功令Bob相信Eve给出的公钥属于Alice。那么,Eve就能伪造由Alice产生的消息。
这就引出了一个悠久而神秘莫测的领域——密钥分发(key distribution)基础设施。你并不是要一个人走这条路,那些准备充分的先锋们已经在这条路上失败多次。在下一章(分布式系统的安全)里,我们将讨论密钥分发的问题。现在只需要记住,公钥的美丽魔法倚仗于肮脏而不确定的密钥分发这一基础。
再重复一遍:密码学的益处完全依赖于密钥的保密性。千万不要暴露、分享私钥。在私钥存储上要万分小心。如果私钥丢失,所有使用该私钥的事物都存在风险。任何拾到私钥的人都可以伪装成你本人,并读取你的秘密信息。

之前讲过,加密能保护数据完整性,因为改变后的数据无法正确解密。哈希数据并仅对哈希而不是完整的数据进行加密,可以减少完整性检查的开销。然而,如果想要真正谨慎,并不能仅使用哈希函数,因为存在哈希碰撞(hash collision):不同的模式串产生了相同的哈希。如果攻击人员能够改动模式串,并令其仍然产生相同的哈希,数据就失去了完整性。
使用加密哈希(cryptographic hash)能够确保完整性。加密哈希是一类特殊的哈希,其重要性质有:
·找到两个能产生相同哈希的不同输入在计算上不可行。
·输入的任何改变都会造成无法预测的哈希值改变。
·仅基于哈希值去推断输入是计算上不可行的。
如果只在意完整性而不是秘密性,可以只在对数据进行加密哈希后,仅对哈希加密,并发送未加密的数据和加密后的哈希给对方。假若敌方故意搞坏数据,当他解密哈希值以后,将解密的哈希与接收到的数据进行哈希后的结果比较,会发现不匹配。
为何需要对加密哈希值进行加密?因为任何人都可以对一切数据运行加密哈希算法,包括改动后的信息。如果不加密信息,(在数据传送途中)攻击者自然可以改变信息并将改变后的哈希填入,再进行发送。于是,篡改后的数据在接收方看来也是未被篡改的。如果加密了加密哈希值,攻击者就不知道数据被篡改以后应当填入怎样的哈希值(记住:只有接收方才可以通过私钥解密并得到正确的哈希值)。
形式化地说,为了执行加密哈希,我们取得明文P和哈希算法H()。注意:没有密钥参与。即

S=H§
加密哈希是哈希的子集。通常S远远短于P。所以,会存在碰撞,即H§=H(P^’ )=S, P≠P’。然而,加密哈希的性质决定了敌方难以利用碰撞:即便已知S和P,构造具有相同哈希S的不同明文P’也是困难的。明文P’的哈希S’很容易得出,只要对P’运行一次加密哈希就可以了。但是,即便P到P’只有一点点改动,S到S^'的改变也是无法预测的。
加密哈希也可以用于其它目的:可以供加盐哈希密码使用,也能用于判定存储的文件是否有被改动。Tripwire等安全软件提供这类功能。它们也能用于强制一个进程在提交请求前执行一定数量的工作,即“工作量证明”(proof of work)。请求提交者被要求提交一个请求,其经过某种加密哈希运算后,具有指定的哈希值。这就要求它们在找到一段能够得到指定哈希值的请求之前,尝试极其多的请求。每次哈希都需要一定的时间,因此,在提交一次正确的请求之前,它们肯定已经做足了一定数量的工作。出现这种用途的应用有:阻止垃圾邮件(或滥用其它资源与服务等,如果使用者确实舍得花费这样的成本,就说明他们的确有这样的需求)和区块链(blockchain)。
与其它加密算法一样,建议使用标准的加密哈希算法。例如,SHA-3算法通常被认为是一种好的选择。然而,一些历史上的加密哈希已经废弃。如果你设计的系统需要加密哈希,明智的做法是:首先检查哪些算法在当前被推荐。

2017年,5名密码学家组成的团队给出了一个轰动全球的SHA-1破解实例(“我们从实用角度破解了SHA-1”):有两份具有实际意义的PDF文档,它们的SHA-1哈希值完全相同。https://shattered.io/ 网站给出了这两个PDF,它们的内容分别是:

可以验证,它们的SHA-1居然是一模一样的!

我们知道,虽然已经能在不算特别长的时间内给出在不少哈希(如MD5)运算后具有相同哈希值的两段信息,但至少它们中的一条是杂乱无章的,无法被人类用于实际用途。例如,给出了与一张图片具有相同的某种哈希的一个文件,但这个文件并无法按照图片的格式打开——会直接报错,或者打开以后只能显示眼花缭乱的内容,看不出任何有用的信息。令人震惊的是,这两份PDF结构清晰、内容正常,而它们的SHA-1哈希没有任何区别!
团队给出的工作是:有两段具备特定结构的数据D_1=P∥M_1,1∥M_1,2∥S和D_2=P∥M_2,1∥M_2,2∥S,它们具备相同的前缀P和后缀S。当M_1,1,   M_1,2,   M_2,1,   M_2,2不同时,有可能

“SHA-1” (D_1 )=“SHA-1” (D_2 )
团队按照PDF文件的编码格式,给出了符合如上条件且具有人类直接可读的意义的数据,最终构造出了SHA-1哈希值相同、内容不同的、具备实际用途的PDF文件。
虽然团队给出的碰撞方法的复杂度并不是最低的,但他们公布的是实际意义的碰撞,更是世界首次。毫无疑问,这是极其亮眼的。
2005年,山东大学数学系教授王小云指出了SHA-1存在的漏洞。当时,杂志《New Scientist》(《新科学家》)破天荒地当了一回标题党,发表了一篇文章《Busted! A crisis in cryptography》(《炸裂!密码学的一场危机》)。文章称,SHA-1几乎是计算机安全的顶峰(pretty much the pinnacle of computer security)。SHA-1算法由美国国家安全局(US NSA)发明并认可,并在安全应用中有着极其广泛的使用。而后,学者们开始寻找更高效的SHA-1碰撞方法。许多公司开始自发呼吁:放弃SHA-1,并建议使用更强的哈希函数。2011年,美国国家标准研究院(NIST)提出,反对使用SHA-1算法,要求使用更安全的哈希函数。
网站在2017年指出,一部智能手机,已经能够在30秒以内给出具有相同MD5值的两段不同的信息。若暴力穷举,使用1200万块GPU,1年内即可给出1个SHA-1碰撞。按照论文给出的方法寻找SHA-1的碰撞,使用110块GPU,同样在1年以内就可以给出来。今年是2021年,相同数量的GPU能够达到的算力只增不减,更何况还有专门针对哈希等运算的ASIC不断问世。因此,SHA-1在许多领域已然不安全,包括但不限于:文档签名、HTTPS(加密保护的HTTP版本)证书、版本管理和备份。
甚至有根据此论文实现的网站SHA1 collider (alf.nu),能够使用不同的图片(要求必须是JPG,小于64 KB,且长宽比尽量相同)生成2份内容不同但SHA-1相同的PDF(某些放入PDF中的图片内容会有变动,原因不明):

你可能听说过一些破解加密的人。在电影和电视中,这是一个很流行的主题。你对此应当有多大的担忧呢?
如果你没有听从早前的建议,继续构建自己的密码算法,那么你应该十分担心了,这种担心足够令你停止阅读本文,把你自己的密码算法从系统中扯掉,并用一个熟知而被认可的标准替换它。接着读下去吧,你回头的时候,我们依然在这里。
如果你使用了那些现代标准,情况很可能OK:除了某些不重要的异常情形,并没有已知的方式,在密钥未知时,读取用这些算法加密的数据。不是说你的系统就安全了,而是说很可能没有人能通过破解加密算法来侵入系统。
他们会如何做?大概是,利用你系统中的与加密无关的软件缺陷,或者,也有概率通过获得你的密钥,或利用加密管理中的其它漏洞。创建和使用密钥的漏洞是一个很常见的问题。在分布式环境中,密钥分发方法中的缺陷也是可以被利用的一个常见缺陷。Peter Gutmann做了一个很好的关于不正确进行加密管理经常引发的问题的调查。例子包括:在被许多人共享的软件中分发密钥;在网络中传输密钥的明文;在比全部可能的密钥集更小的集合中抽取,而不在整个理论上可能的集合中抽取。较近的例子,心脏出血攻击(Heartbleed attack)表明了一种从远程计算机内存中的OpenSSL会话中获得密钥的方式,尽管密码算法及其实现以及密钥选择过程都没有漏洞。该漏洞允许攻击者读取1/4到1/2的HTTPS站点的流量。
攻击者应对加密的一种方式是:猜密钥。这样做一点也不算破解加密。加密算法是被设计为阻止不知道密钥的人们获得秘密的。如果知道密钥,解密就不困难。
一个攻击者可以仅仅简单猜测每种可能的密钥并尝试。这称为暴力攻击(brute force attack),也是必须使用长密钥的原因。例如,AES密钥至少128-bit。假设随机生成AES密钥(设随机数的产生过程没有漏洞),攻击者平均要猜测2127次才会猜中。显然,花费的时间是极多的。不过,要是一个软件缺陷令密钥只在32个AES密钥中产生,暴力攻击就十分容易。密钥选择是加密的一件大事。

对于公钥加密,需要运行算法去选择你要使用的可能性最小的密钥对。对于对称加密,则可以选择任何可能的密钥。如何选择呢?
随机选择。如果使用任何确定性的方法选择密钥,敌方面临的找出密钥这个问题,就被转化成了找出产生密钥的方法。方法一旦被搞出来了,他就能得知全部可能的密钥。如果随机生成密钥,那么获得一个密钥对获得其它密钥并没有帮助。加密系统的这个特性称为完美前向保密(perfect forward secrecy)。
不幸的是,真正的随机性难以得到。操作系统的最佳随机数来源是:检测被相信是在自然界随机的硬件过程,例如,某个硬件执行运算的时间的低阶位,或热噪声、量子力学效应、放射性元素的衰变辐射,等等,并将检测结果转化为随机数。这称为熵聚集(gathering entropy)。在Linux系统中,这已经自动完成了。可以读取/dev/random来使用熵聚集。Windows也具备类似的特性。可以使用它们去生成密钥。虽然并不完美,但也足够用于许多目的了。

原有的802.11无线网络标准并不包括对在空气中传输的数据的加密保护。添加这类保护的第一次尝试称为有线等效协议(Wired Equivalent Protocol,WEP)——挺乐观的名字。WEP受限于与已有标准配合的需要,其生成并分发对称密钥的方法具有严重的漏洞。仅通过监听802.11网络的无线流量,攻击者就可以在1分钟内确定使用的密钥。有许多可用的工具允许任何人这样做。
WEP被Wi-Fi保护访问(Wi-Fi Protected Access,WPA)替代了。不幸的是,WPA被证明具有自己的弱点,因此它又被WPA2替代。更不幸的是,WPA2也被证明具备自己的弱点,因此它于2018年被WPA3替代。为无线网络提供加密这个过程的悲惨命运,应当作为每个被诱导而低估将这件事做好的困难的人都要上的一课。
另一个事例是,Netscape Web浏览器的一个早期实现版本使用一些容易被猜中的值作为随机数生成器的种子来生成加密密钥,例如时间和请求密钥的进程ID。研究人员发现,他们能在大约30秒以内就猜中产生的密钥。
你可能听说过一些公钥加密系统使用长得多的密钥,例如2 KB到4 KB。然而,你并不能为这类加密系统随机选择密钥。只有相对较少的公钥私钥对是可选的。这是因为公钥和私钥对必须与对方相关。关系通常是数学上的,且难以推导。只是,手持公钥时,一个人总是可以通过系统的数学性质,最终推导出私钥来。这就是为何公钥加密系统都使用如此长的密钥。
很多嵌入式设备的制造商使用公钥加密保护设备,设备的软件中含有一个私钥。但经常发生的是,同一型号的所有设备都使用相同的私钥。这种共享的私钥终将变得公开。2016年9月,一项研究显示,450万嵌入式设备使用的私钥不再特别私密。任何人都可以伪装成这些设备来实现任意的目的,并使用私钥读取任何发送给他们的信息。本质上,这些设备进行的加密几乎不比粉饰要多,并没有以任何可接受的幅度增加设备的安全性。
总的来说,破解加密通常就是关于获取密钥。因此,再次强调:密码学的益处完全依赖于密钥的保密性。

加密是迷人的,但很多东西也是迷人的,即便与操作系统无关。为何我们使用如此长的篇幅讲述加密呢?因为加密能用于保护操作系统。
密钥的秘密性对有效使用加密是必不可少的,我们已经把这一点锤进了你的脑袋。回忆之前的章节,操作系统对于一台计算机的全部资源都具有控制权和访问权。这暗示了:如果加密了计算机上的信息,又有必要在同一台计算机上解密,那么操作系统可以解密数据。但要记住,硬件不允许操作系统对安全区域内的信息具备完全的访问权。
无论你是否信任你的操作系统——如果不,那么无论如何,生活就变得不悦了。但有一种暗示是:不受信任的操作系统,一旦能够访问你的密钥,就能复制和随时随地重用。这个观察与任何你将数据交给你不信任的事物的情况都有相关。举例:如果不信任数据所在的云计算设施,你自然就不会提供明文数据给它们,并让它们加密。它们会看到明文,并能够存储密钥的副本。
如果你现在确定你的操作系统是可信的,但担心之后可能就不可信,那么现在可以立即加密一些东西,并确保密钥不存储在本机。当然,如果你错了,或在操作系统变坏后,在这台机上解密了数据,你的加密就不能保护你了,因为极其重要的密钥秘密性已经不复存在。
一个人可以认为,并不是操作系统遭受的全部侵害都是永久的。很多都是,但一部分会给予攻击者系统资源或特定资源的临时访问权限。这些情况中,如果加密数据没有明文存储,解密密钥在当时也无法由攻击者访问,加密数据也许还是能提供益处。棘手的问题是,无法提前得知对系统的成功攻击是否仅在特定的时间内发生,仅持续一定的时间段,或仅针对系统的特定元素。因此,如果采用此方法,你会想将暴露减少到最低:不经常解密,小心而尽快地丢弃明文数据,并且不要将密钥的明文存在系统中,除非需要进行加密操作。但是这种最小化是难以达成的。
如果加密并不能完全保护我们免受不诚实的操作系统的影响,加密在操作系统中的用处又是什么呢?有一个特例。一些加密操作是单向的:仅加密,而从不解密。我们能这样子去存储密码的加密形式,即便操作系统叛变了。因为加密后的密码无法解密。但是,如果合法用户提供了正确的密码,叛变后的操作系统就会在对密码使用加密哈希进行单向加密之前,将密码复制,然后交给幕后的坏人们。
在分布式环境中,假如在一台机上加密了数据,并传送到网络,所有中间部件都不是我们的机器的一部分,于是没有密钥的访问权。数据在传输中将受到保护。当然,最终的目的计算机上的伙伴会需要密钥以使用数据。之前讲过,这会在之后的章节(分布式系统的安全)中讨论。

如果有人能绕过操作系统而直接访问硬件,假如存储在硬件上的数据是加密的,密钥也不在硬件上,加密将可以保护数据。这种加密称为静止数据加密(at-rest data encryption),以与加密数据并在机器之间传输进行区分。
为了确保数据的秘密性或完整性等性质,一个技巧就是不要存储明文,而存储加密形式。当然,加密的数据在许多计算中都不能使用,因此如果需要对数据进行通用计算,数据就必须要解密。假设仅需要安全地存储数据的副本而不是使用,解密可能不是必要的。但这并不算是常见情况。
关于计算前的解密,有一个例外。密码学的奇才们创立了一种加密形式,称为同态加密(homomorphic cryptography),允许直接使用加密后的数据进行计算,而不需解密。解密以后,就能直接看到计算后的结果(看不到参与运算的数据)。同态密码算法有所发展,但具备高昂的存储成本与算力需求,使得它们对相当多的目的都不实用。至少到撰写本章时,都是如此。也许随着时间的推移,情况会改变。

数据能以不同的形式、使用不同的密码算法(DES、AES、Blowfish等)、以不同的粒度(记录、数据库、文件、文件系统,等等)、由不同的系统部件(应用、库、文件系统、设备驱动,等等)加密。一种常用的静止数据加密是全盘加密(full disk encryption)。这意味着存储设备的(几乎)全部内容都被加密了。尽管有着这样的名称,这个手段也能用于其它永久存储媒体,而不仅仅是机械硬盘。全盘加密在硬件(内建到存储设备里)和软件(设备驱动,或文件系统的某个元素)中通常都有提供。无论何种情形,操作系统都在提供的保护中充当有角色。Windows BitLocker和Apple的FileVault都是基于软件的全盘加密。
一般地,在启动的时候,会要求用户提供解密密钥或用于获取密钥的信息(例如密码短语,passphrase,它与密码相像,但可能包含多个单词)。提供正确信息后,解密需要的密钥就(对硬件或操作系统)可用了。数据位于设备上时,它们被加密。数据移出设备时,就被解密。只要数据被存储在机器内存中的任何位置,包括共享缓冲区和用户地址空间,数据就都保持加密。当新数据被发送到设备时,它首次被加密。数据从不在存储设备上存储解密形式。在首次请求获得解密密钥后,加密和解密过程就对用户与应用程序透明。他们从来不会看到加密形式的数据,也不会再被要求提供密钥,直到机器重启动。
加密的计算花销大,尤其是用软件执行的时候。执行基于软件的全盘加密时,将带来额外开销。开销的量各有不同,但在磁盘负载重的操作中,百分之几的额外延迟是常有的。对利用磁盘更少的操作,额外开销或许感觉不到。对于基于硬件的全盘加密,磁盘依然可以达到不使用全盘加密时的标称速率。
这种加密形式不防御什么呢?
·它不对试图访问不允许查看的数据的用户提供额外保护,无论操作系统是否提供的标准的访问控制机制:若是,用户缺少权限,访问被拒绝;若否,用户被提供与其他人同等的解密密钥的使用。
·它不为应用程序中可能泄露数据的漏洞提供保护。这种漏洞允许攻击者伪装为相应的用户。如果用户能访问未加密的数据,攻击者也可以。例如,它无法防止缓冲区溢出和SQL注入(SQL injection)。
·它不防护系统中的不诚实的特权用户。超级管理员的特权可能允许他作为拥有某些数据的用户去访问数据,或允许安装一些提供用户数据访问的系统组件。因此,超级管理员能够访问数据的解密副本。
·它不防护操作系统本身的安全漏洞。一旦提供了密钥,它就对操作系统可用,无论是直接存储在内存中(直接可用),或者要求硬件去使用(间接可用),无论操作系统是安全的、受到了攻击的,还是不安全的。
这种加密形式能提供什么好处呢?设想:一台存储设备物理地从一台机移动到另一台机,另一台机的操作系统并没有义务使用设备上存储的访问控制信息。实际上,它甚至不需要使用相同的文件系统访问此设备。例如,它可以直接将设备当作RAW数据块,而不是有组织的文件系统的来源。所以,与设备上的文件相关的访问控制信息可能被新操作系统忽略。
然而,如果设备上的数据是全盘加密的,新机器通常就无法获得加密密钥。它能访问RAW块,但块是被加密的,没有密钥而无法解密。如果硬件被窃取并安装到另一台机器上,这个好处很有用。对于移动设备,这种可能性非常真实,因为它们经常丢失或被偷窃。磁盘驱动器有时会被重新销售,之前的所有者的数据(包括相当敏感的数据)可能会被再次购买的人员发现。这些都是全盘加密能提供真正的益处的例子。
对于其它形式的静止数据加密,系统仍然必须处理这些问题:加密的成本、如何获得密钥、何时加密或解密,不同处理会得到不同的保护结果。一般地,这类情况要求一些软件保证:未加密的数据不再存储于其它位置,包括缓存,并且加密密钥对不正当访问数据的人员不可用。这类保护产生价值的情况相对更少,但也有常见的案例:
·存档(archive)一些需要复制并保留但不需要被使用的数据。这种情况下,数据能在创建时加密,可能从不被解密,或只在特定情况时,在数据拥有者的控制下解密。如果机器在首次加密时未被侵入,且密钥不是永久存储在系统中,那么加密数据相当安全。注意:假如密钥丢失,你将永远无法解密存档的数据。
·在云计算设施中储存敏感数据。这是上一个情况的变体。如果不完全信任云计算提供商(或不确定提供商的谨慎程度——记住,当你信任另一个计算元素时,意味着你不仅信任它的诚实,还信任它的小心与正确性),在将数据发送给云设施之前进行加密是明智的。许多云备份产品都支持这个能力。这时,加密和密钥使用都在将数据移动到不受信任的系统之前,或从系统恢复数据之后。
·通过应用程序执行的用户级加密。例如,用户可能选择加密一封邮件。此时,加密由应用程序执行,用户执行某些动作,令密钥对应用程序可用。理想情况下,应用程序确保加密前的数据和用于加密的密钥在加密完成后都不再可用。然而,记住,当密钥存在时,操作系统能在应用程序不知情的情况下,获得对它的访问权。
之前说过,加密选定的静止数据的一个重要的特殊情况是:使用密码保险柜(password vault)或密钥环(key ring)。典型的用户与许多远程站点交互,站点们要求提供密码。如果为每个站点使用不同的密码,安全性是最佳的。但这会给人类用户带来负担。记忆大量的密码一般都很困难。一个解决方案就是:加密不同的密码并保存在机器上,由对应的站点索引。当要求某个网站的密码,就解密相应的密码并提供给站点。
系统必须有某种方法,在任何数据需要加密或解密的时刻,获得需要的密钥。如果攻击者获得了密钥,加密就没有用了,因此密钥的安全存储变得关键。典型地,如果密钥在计算机的其它位置以未加密的形式存储,加密的数据就有风险,因此设计良好的加密系统不这么做。例如,解密密码保险柜的密钥不保存在机器的稳定存储中,而是在需要时询问用户,或要求提供能推导出密钥的密码短语。而后,密钥被用于解密需要的密码。最大安全性将会建议:在解密完成后就销毁密钥(记得最少特权原则吗?),但这会令用户在每次需要用到密码时重新输入密钥(记得可接受性原则吗?)。关于可用性和安全性的一种折中是:在一段时间内记录第一次输入的密钥,但仅保存在RAM中。用户退出登录后,系统关机,或管理密码保险柜的应用程序(例如浏览器)退出后,忘记密钥。这种方法在单次登录系统中显得怀旧:用户在系统第一次被访问时才被要求输入密码,但直到注销之前,都不再需要身份验证。它与那些系统一样也有相同的缺点,例如:允许无人值守的终端为未授权的一方凭借其他用户的访问许可使用。它们都具有相当大的优点:不过多烦扰用户。无论怎样,它们被抛弃了,因为有利于不提供安全的系统。

回忆一下:访问控制和能力不能被交到用户手中,否则用户可以伪造它们,并授权他们自己访问任何想访问的东西。可信的实体能够使用加密来创建足够长且安全的、指明拥有者被允许访问特定资源的数据结构。这个数据结构可以被交付给用户,用户可能将其展示给资源的所有者以获取访问权限。实际控制资源的系统必须有能力在授权访问之前检查数据结构的有效性,而不需要维护访问控制列表。
这种加密的能力能通过对称加密或公钥加密来创建。使用对称加密时,能力的创建者和检查能力的系统都需要共享相同的密钥,否则就可能要求在很高的速率和规模(依赖于使用场景)在需要密钥的机器之间移动密钥。你可能会好奇:为何一台机器宁愿创建加密的能力去批准访问,而不仅仅是记住用户已经通过了访问检查呢?理由有几点。例如,如果控制资源的机器与大量的用户一同工作,追踪每个用户的访问状态是高开销且复杂的,尤其是在系统需要考虑失败与延迟的分布式环境下。或者,如果系统希望提供可以转移的访问权限,因为安全主体可能从一台机移动到另一台机,允许能力随着安全主体移动并在任何位置都能使用,显得更加可行。对称加密的能力,在所有创建和检查它们的机器都被天然地信任、密钥分发不是问题的时候,也有它的道理。
如果公钥加密被用于创建能力,创建者和资源控制者都不需要位于相同的位置,信任关系也不需要很强。能力创建者需要一个密钥(一般是私钥),资源控制者需要另一密钥。如果能力的内容本身不是秘密,真正的公钥就能被使用,无需担心到底是谁知道它。如果要求秘密性(或者,至少是一定程度的隐匿性,obscurity),公钥只能分发给数量受限的一组需要检查能力的实体。假使将密钥嵌入了广泛分布的软件中,你可以预计密钥会变得公开。因此,即使你相信密钥是秘密的,也不要因为这样的相信而过于放松。资源管理者可以创建一组凭据(指出哪些主体允许以何种方式在哪些时间使用何种资源),然后用私钥加密它们。其他人可以通过使用管理者的公钥来解密,验证凭据的有效性。由于只有资源管理员知道私钥,没有人能够伪造能力。
这种加密的能力能够存储大量的信息,包括过期时间、被授予能力的一方的身份,等等。由于强加密会确保全部这种信息的完整性,能力就可以被依赖。这个特性允许能力创建者阻止任意复制和共享能力(至少是某种程度上)。比如,在网络上下文中使用的一种加密能力能与特定的IP地址绑定,仅在携带它的报文来自指定的IP地址时,才被认为有效。
许多不同的加密策略也可以使用。重要的一点是,加密的能力必须足够长,使得通过暴力枚举或随机猜测来获得一个有效的能力在计算上不可行。
在后续的章节(分布式系统的安全)中,将叙述更多的关于加密能力的内容。

猜你喜欢

转载自blog.csdn.net/COFACTOR/article/details/120321144
今日推荐