gitbook/实用密码学/docs/316802.md
2022-09-03 22:05:03 +08:00

168 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 06对称密钥如何保护私密数据
你好,我是范学雷。
在上一个模块,我们学习了单向散列函数。从今天开始,我们将开启一个新的模块,在这个模块里,我将跟你讨论加密技术的相关知识。是不是感觉上一个模块的学习还意犹未尽?
别着急,单向散列函数还会出现在我们的视野里。那么,加密技术是用来做什么的呢?
还记得上一讲,我们讨论了单向散列函数的使用场景吗?其中,**一个重要的限制是****我们****需要确保给定的散列值不能被修改**。这个简单、直观的限制,给单向散列函数的使用套上了一个紧箍咒。
这说明在很多场景下,我们并不能仅仅使用单向散列函数来解决数据的完整性问题。要想去掉这个紧箍咒,扩大单向散列函数的适用场景,我们还需要其他技术,比如加密技术。
那加密技术是怎么帮助单向散列函数解决完整性问题的?这个疑问立即就来到了我们面前。不过不用担心,我们需要一点时间来了解这个问题,以及解决问题的办法。
今天,我们先来讨论第一类加密技术:对称加密技术。
## 什么是加密?
在讨论对称加密技术之前,我们要先了解加密、解密和密钥这几个概念。
其实这几个概念还是很容易理解的。把信息或者数据伪装、隐藏起来,转换成难以解释的信息或者数据,这个过程叫做**加密**。和加密这个过程相反的过程,就叫做**解密**。
一般来说,加密产生的那个难以解释的信息或者数据,我们把它叫做**密文Ciphertext**。对应的,加密前的数据,我们通常把它叫做**明文Plaintext**。
密文信息通常看起来都是晦涩难懂、毫无逻辑的,所以我们一般会通过传输或者存储密文信息,来保护私密数据。当然,这建立在一个假设基础上:没有经过授权的人或者机器,很难通过密文计算出明文;经过授权的人或者机器,才能够通过密文计算出明文。
那经过授权的人或者机器,是怎样通过密文计算出明文的?对,就是使用**密钥**。
在现代密码学里,**密钥是在加密和解密运算里,决定运算结果的一段信息**。因为,加密要使用密钥把明文信息转换为密文;解密要使用密钥把密文复原为明文。
也就是说,加密运算需要两个输入:密钥和明文。
![](https://static001.geekbang.org/resource/image/d1/51/d1642ccc8074434a09d41cf8c360af51.jpg)
解密运算也需要两个输入:密钥和密文。
![](https://static001.geekbang.org/resource/image/6b/1a/6bff070fd3a2c96cc7b4caed4052d61a.jpg)
如果没有密钥,我们就没有办法执行解密运算,也就很难把密文转换成明文。同理,如果只有授权的人或者机器才知道密钥,那么没有授权的人也很难通过密文计算出明文。
你可能会觉得,密钥太重要了!但现代密码学之前的加密,其实不是这样设计的。
历史上的加密,是没有密钥的。数据的保密性,依赖于算法的保密性。一旦算法被破解,数据也就被破解了。如果有一天,时光穿梭机真的实现了,我们穿越回去,偷听一下、偷看一下当初设计者的算法设计,算法就被破解了(时光穿梭机的梗,你可以自己搜索一下)。
其实也用不着这么科幻,就算时光穿梭机实现不了,我们也还有很多更有效的办法:
* 当初算法的设计者还健在吗?
* 当初算法的实现者还健在吗?
* 算法实现的代码还在吗?
* 算法运行的环境还在吗?
解决掉其中任何一个问题,我们就能破坏掉算法的保密性。而且,这些破解办法通常没有什么难度,比制造时光机有效率多了。除此之外,还要说一点,虽然算法保密看起来很安全,但是这也意味着只有很少的人知道算法,这样的算法质量也是值得担忧的。
**到了****现代密码学,加密数据的安全性就****依赖于加密算法的质量和密钥的保密性这两个因素**。密钥部分,是私有的部分,需要严格保密;算法部分,变成了公开的部分,要接受公开讨论、评测,接受各种分析和攻击。**一个算法,如果****在****接受****了****公开的分析、评测和各种各样的攻击****之后****,还依然被认为是安全的,****我们才能说,这个算法****的安全性是真的经得起考验的。**
为什么算法一定要公开?不公开不行吗?为了可以让你更直观地了解使用公开算法有多重要,我们一起来看看公开算法的遴选过程是怎样的。
![](https://static001.geekbang.org/resource/image/fd/a1/fd0074a5351eb4be97c2ea3e795aa3a1.jpeg)
所以你看仅仅单向散列函数的遴选就花费了7年时间还聚集了世界上最出色的密码学家和密码分析专家。在遴选标准中有一个重要指标就是有没有足够多的密码分析。
什么是密码分析?**密码分析,指的是分析、评测一个密码学算法,有没有安全缺陷和适用场景的限制。如果一个算法,没有人对它展开分析、评测,或者缺少足够的分析,它的安全性很难获得信任**。63个落选的算法中不乏知名密码学专家或者知名团队和组织的撑腰。
我相信,这些算法在提交之前,它的发明者都是信心满满的。可是一旦接受了公开的分析和评测,很多意想不到的安全缺陷就暴露出来了。
但是,保密的算法,如果没有经过大量密码分析专家的分析,是很难给人信心的。可如果经过了大量的、不同的密码分析专家的分析,保密算法也算不上保密了。的确,这是一件很矛盾的事情,有时候却又不得不这样。
所以,渐渐地,**使用公开的算法****是****密码学领域的****一个****基本常识。****不过,一个****现代密码学算法的安全性,都是基于密钥的保密,而不是算法保密要求**。遗憾的是,仍然有很多保密算法的存在和使用。对于这样的使用,我们很难有信心相信它的安全性。
为什么我们要花费这么大篇幅去讨论公开算法的遴选过程呢?
其实是因为,我想让你对以下两个密码学常识留下深刻的印象:
* **不要自己发明密码算法,尤其是****在****没有经过充分讨论、充分分析的情况下**。大部分情况下,我们自行发明的密码学算法都是灾难。
* **不要把安全性寄托在算法的保密上**。大部分情况下,保密的算法都是无法保密,并且是不堪分析的。
在这个部分里,我最后再强调一下:**现代的密码学算法的安全性,都是基于密钥的保密,而不是算法保密要求**。管理好密钥,做好密钥的保密,才是密码学系统最关键的任务。
## 什么是对称密钥?
讨论完加密和密钥,我们就要来看看对称密钥技术。
说起来对称密钥就不得不提它的对立面非对称密钥。1976年惠特菲尔德·迪菲Whitfield Diffie、马丁·赫尔曼Martin Hellman发表了基于非对称密钥技术的密钥交换算法但是在这之前并没有对称密钥、非对称密钥的说法。
1976年之前密码学就是一门研究对称密钥的学问。所以我们看的二战时期的谍战片如果里面提到了发报机和密钥用的肯定不会是非对称密钥技术。这种影响到现在还有比如当我们使用密钥这个词汇时一般指的就是对称密钥。
**对称密钥,顾名思义,就是每一个参与者都持有相同的密钥,使用相同的密钥。**
![](https://static001.geekbang.org/resource/image/e6/c3/e6eb19e271ecce7bedf629792d7ddfc3.jpeg)
**非对称密钥,****就是指****每一个参与者都持有不同的密钥,使用不同的密钥。**
![](https://static001.geekbang.org/resource/image/ba/eb/bab7b6ae0c35d2a5dbb56c32d3f139eb.jpeg)
经常有人问我,密码属于对称密钥技术吗?如果属于的话,为什么密码学不叫密钥学?密码和密钥有什么区别吗?所以,在这里,我要稍微地强调一下。
密钥和密码是两个特别容易混淆,而且经常混淆的概念。比如密码学明明是研究密钥的,偏偏叫“密码”学;密码分析明明是研究加密算法的,偏偏叫“密码”分析。怎么理解呢?
有一个技巧,就是**借助英语词汇**这两个概念一下子就会清晰。通常地密码的英语词汇是Password加解密算法的英语词汇是Cipher密钥的英语词汇是Key。
密码Password使用中文里的“口令”更为贴切。比如三国时期的曹操据说就使用过“鸡肋”作为口令。口令该怎么用呢如果执勤的士兵问“口令”杨修回答“鸡肋”这就可以获得通行许可了。如果回答的不是“鸡肋”就不能获得通行还可能被逮起来进一步审查。
和对称密钥类似,需要每一个参与者都知道相同的口令,使用相同的口令。
而密钥Key和密码Password的区别在于它们的用法。口令的用法是对照口令本身。士兵知道口令是“鸡肋”然后对照他人的回答是不是“鸡肋”。
我们上网输入的用户名和密码,也是系统要直接地或者间接地进行对照,登录者是不是使用了系统记录的口令。而密钥的用法,则是参与加密运算或者解密运算。
通常地,我们也不用纠结别人是不是能准确地使用好“密码”和“密钥”这两个词汇。我们只要从它们的使用场景来判断,到底是用作对比的口令,还是用来运算的密钥就好。
另外在生活中我们总是在记口令比如我们登录网站的密码。和自然界其他生物相比人类的记忆能力值得自豪。我们通常可以记住六位的数字或者学过的单词。不过即便如此我们还是倾向于选择“123456” “888888”或者生日这样的简单口令。
稍微复杂的口令,就超越我们的记忆能力了,更别提要记住很多网站的很多口令了。在现代计算机的眼里,这样的记忆能力实在太渣了,用最不讲究技巧的蛮力攻击也就是分分钟钟的事情。
密码需要记但是一般来说我们不需要记住密钥事实上我们也记不住。现代的密钥通常需要至少128位没有规律的字符而且频繁更换。比如下面的5个密钥其实是质量不太好的、便于记住的128位的密钥你可以挑战挑战看看能不能记得住
```
密码1: Yq3t6w9z$C&F)J@N
密码2: gVkYp3s6v9y$B&E)
密码3: NdRgUkXp2s5v8y/B
密码4: -JaNcRfUjXn2r5u8
密码5: C&F)J@NcQfTjWnZr
```
我们当然记不住这么复杂的密钥,除非是不世的天才。所以,我们才要拜托计算机替我们记住这么复杂的信息,并且自动地更换。
## 密钥管理的烦恼
如果我们拜托计算机替我们管理密钥,方便是方便了,但是也会立即衍生出很多现实的问题:
* 计算机替我们记住了密钥,计算机能够保持密钥的保密性吗?
* 计算机会不会出卖我们?
* 使用密码的程序会不会泄漏密钥?
* 运行算法的环境能不能泄漏密钥?
* 退役的机器里,会不会有密钥存留导致密钥泄漏?
* ……
无论哪个问题没有处理好,密钥的保密性可能都只是空谈。
**既然现代的密码学算法的安全性依赖于密钥的保密,那么,管理好密钥,做好密钥的保密,就是密码学系统最关键的任务**。不过,密钥的管理,部分内容已经超出了密码学的范畴,我们需要在计算机基础的操作系统和编程语言里找答案。
比如,在[《代码精进之路》](https://time.geekbang.org/column/intro/100019601)里,我们提到的管理敏感信息的原则,同样适用于密钥的管理。要把密钥当作超级敏感的信息来看待,在我们的代码里保护好密钥,不要泄漏密钥信息。
之后,我们还会讨论对称密钥的管理,以及怎么使用密码学的技术降低密钥管理的难度和风险。
像单向散列函数一样,不同的加密算法也有不同的安全强度。那么,到底哪些对称密钥的算法是我们可以信赖的呢?这是我们下一次要讨论的问题。
## Take Away今日收获
今天,我们讨论了什么是加密解密、什么是对称密钥、密钥保密的必要性,以及密钥管理的困难。通过今天的讨论,我们知道要把密钥当作超级敏感的信息来处理。
这需要我们在编写代码的时候要特别留意密钥的无意识泄露以及在内存、硬盘里的长时间驻留。比如说用完密钥后我们的代码一定要把密钥占用的内存清零而不要依赖类似Java垃圾收集器这样的机制。再比如说我们千万不能把密钥写到系统或者应用的日志里日志可是泄露密钥的最便捷路径之一。
通过今天的讨论,我们要:
* 理解什么是对称密钥;
* 知道对称密钥的安全性,取决于密钥的保密性和算法的安全性,而不是算法的保密性。
* 要把密钥当作超级敏感的信息来处理,做好密钥的保密。
## 思考题
你还见过哪些坑?处理敏感信息,你有哪些经验?另外,你有没有发明过密码算法?你了解的项目有没有发明过密码算法?这些算法有能够替代的公开算法吗?
欢迎在留言区留言,分享你的经验。参与讨论的人越多,我们互相学习、互相启发的就越多。
好的,今天就这样,我们下次再聊。