<audio id="audio" title="17 | 加密密钥是怎么来的？" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/bf/05/bfba9a7f7a86a357d1fa23680933a805.mp3"></audio>

你好，我是范学雷。

到目前为止，你已经跟我一起走了很长的路了。不知道这一路上，你有了哪些心得和体会？对密码学是不是多了很多新的认知和想法？这一讲，我们继续上路，踏足密码学的世界。

前几讲，我们花了很长时间讨论了对称密钥的算法，以及使用对称密钥算法要注意哪些陷阱。但是，不知道你有没有注意到，一直有一个悬而未决的问题。

我们要使用对称密钥算法，总得有对称密钥吧。那么，对称密钥是从哪儿来的？这是我们这一次要讨论的问题。

# 合格的对称密钥什么样？

对称密钥从哪里来的？在讨论这个问题之前，我们先要弄清楚另外一个问题。一个合格的对称密钥，应该满足什么样的条件呢？只有知道了需求，我们才能有解决的方案。

## 对称密钥的长度

还记得我们之前提到过的AES-128和AES-256算法吗？

其中的128和256，指的是密钥的长度。也就是说，AES-128需要128位的密钥，AES-256需要256位的密钥。一般来说，一个对称密钥算法的密钥长度是固定的。这就是对称密钥的第一个要求：**对称密钥的长度是由对称密钥算法确定的。**

当然，这并不意味着一个对称密钥只能用于一个加密算法。一个对称密钥，一般可以用于任意一个对称密钥算法，只要这个对称密钥满足算法要求的密钥长度。比如一个256位的对称密钥，既可以用于AES-256，也可以用于ChaCha20。

可是，一个对称密钥用于两个不同算法，这不是我们推荐的用法。因为，我们要考虑算法破解的风险。如果一个算法被破解了，那么它使用的对称密钥可能也就被破解了。我们不希望一个算法的失败连累另一个算法要保护的数据。

所以，大部分的应用程序接口，都不会限制一个对称密钥只能用于一个算法。但是，我们要有意识地避免这种情况。比如说，如果一个对称密钥已经用于AES-256的加密计算了，就不要再把它用于ChaCha20或者其他的加密算法了。

## 对称密钥的强度

说完了对称密钥的长度，我们来看对称密钥的强度。

有印象的话，你应该记得AES-128算法的安全强度是128位，AES-256算法的安全强度是256位。可是，如果没有高质量的对称密钥，这样的安全强度就没有意义。

举个例子，如果密钥只能是阿拉伯数字，那么128位的密钥就只有10^16种可能性。也就是，如果使用蛮力攻击的话，最多需要10^16次尝试，加密密钥就能够找到，加密数据就能够被破解。

如果我们把10^16转换成按位表示的安全强度，也不过就是53位的安全强度，这离128位的安全强度可相差太远了。所以，**对称密钥的强度一定要和加密算法的强度匹配。**比如说吧，AES-128算法需要128位的密钥，这个密钥就要有128位的强度。

对于任意给定的密钥，我们并不一定能够判断它的强度是不是足够。比如说，我们并不能判断“123456”是不是比“135246”强度更大。所以，当我们说密钥强度的时候，其实我们关注的还有产生密钥的机制。

**首先，产生密钥的机制要有匹配的强度。**如果产生密钥的机制只有128位的安全强度，它就不能提供256位安全强度的密钥。简单地说，攻击产生密钥的机制就可以了。

**其次，密钥在它的长度上要均匀分布。也就是说，这个密钥的每一位是0还是1的概率都是50%。如果不能做到均匀分布，就会降低密钥的安全性。**比如说，我们前面提到的阿拉伯数字的密钥，就是密钥没有做到均匀分布，导致安全强度降低的例子。

还有，**密钥生成机制产生的密钥要随机**。也就是说，下一个密钥要均匀分布，而且不可预测。如果下一个密钥不是随机的，那么下一个密钥的安全性就没有保障。如果上一个密钥是“123456”，下一个密钥是“123457”，只是简单地递增，那么这两个密钥都是不合格的密钥。

总结起来就是，**一个合格的对称密钥，它的长度和强度要与对称密钥算法相匹配。**

## 对称密钥的秘密

在[第6讲](https://time.geekbang.org/column/article/316802)，我们提到，密钥的保密性和算法的安全性是对称密钥算法安全的两个关键因素。

既然密钥需要保密，那当然也就意味着密钥有秘可保。没有秘密的密钥当然谈不上保密，不能保密的密钥也没法保护数据的机密性。总之，对称密钥要有秘密。

不过，需要注意的是，秘密也是有安全强度的。比如说，很多地方的民俗，有“猜有无”的酒令。猜的人猜测对方握紧的手里有没有东西。

对于出酒令的人来说，手里有没有东西，当然是一个秘密。但是这个秘密被猜中的几率是50%。如果换算成密码学的指标，也就是只有1位的安全强度。1位的安全强度，当然简单好玩，适合于饮酒助兴。可是只有1位的安全性，并不适合在计算机系统中保护我们的机密数据。

**一个合格的对称密钥，要有足够的秘密，并且它的长度和强度要与对称密钥算法相匹配。**

这三个需求看起来简单、直观，但是用起来很容易就掉进强度错配、无秘可保的坑里。好了，有了这三个需求，对称密钥从哪里来这个问题，我们就可以来一起讨论它了。

# 对称密钥从哪里来？

那么，对称密钥是从哪里来的呢？你可能觉得这个问题有点怪怪的，其实这个问题，换个说法，就是我们去哪里才能够找到长度和强度都符合要求的秘密？

先看秘密的来源，来源主要有两类：

- 一类是计算机用户持有的秘密；
- 另一类是计算机持有的秘密。

对应地，也就是对称密钥的两种来源。

## 用户持有的秘密

计算机用户持有的秘密，主要表现为只有该用户知道的秘密和只有该用户拥有的秘密两种。比如，我们能够记住的用户口令，是只有我们知道的秘密；我们的指纹，是只有我们拥有的信息。

遗憾的是，我们能够记住的密码很短，一般来说，满足不了对称密钥强度的需求；我们拥有的指纹、面容、虹膜信息，都可以复制，保守这样的秘密是一个极具挑战的任务。陌生的场合，我们摸一摸杯子，睁一睁眼睛，露一下面颊，这些所谓的秘密就都不再是秘密了。

我们拥有的生物特征不可靠，我们能够记住的又太少，那为什么指纹识别和用户密码还这么流行呢？主要原因是还是没有更好的、更简单的办法。

从我接触密码学开始，就已经有人喊口令要消亡了。二十多年了，口令依然活得有模有样，指纹/面部识别也越来越流行，尤其是需要身份认证的时候。

## 使用口令生成对称密钥

既然口令的强度不够，那如果一段加密数据，只有用户参与才能解密，那该怎么办呢？**解决的办法就是分级：使用弱的口令来保护强的密钥，然后使用强的密钥来保护私密数据。**

如果加密数据泄漏了，由于保护它的对称密钥有足够的强度，我们不用担心破解的问题。

而口令，主要用于身份认证和衍生密钥。身份认证和密钥衍生，都不是高频次的运算。 从口令推导出来的对称密钥也不保存、不长留。这些措施，都降低了口令破解带来的数据泄漏风险。

<img src="https://static001.geekbang.org/resource/image/2d/b3/2d9ff1f0dc3c3cedb0186c129ccb6fb3.jpeg" alt="">

使用口令生成对称密钥的办法，通常成为“基于口令的密钥推导”。现在常用的基于口令的密钥推导算法是PBKDF2。我不在这里讲这个算法的细节了，你可以自己去找一找相关的规范。

不过，我们需要注意的是，由于口令的安全强度不够，很容易被破解，我们需要经常地变换口令，有些公司是强制性要求。如果口令变换了，从它衍生出来的对称密钥当然也就随着变换了。

如果我们直接使用衍生出来的对称密钥加密数据，每次的口令变化，都需要把已经加密的数据重新加密一遍。这可不是好事情！

<img src="https://static001.geekbang.org/resource/image/8e/99/8e2yyc1d93e05379e3b83b4yy43a8699.jpeg" alt="">

所以，通常地，我们也不推荐使用口令推导出来的密钥直接加密需要留存的数据。有什么办法克服这个障碍呢？解决这个问题，我们还要再添加一个环节。也就是使用推导出的密钥保护一个使用时间更长的密钥；而使用时间更长的密钥用来保护私密数据。

<img src="https://static001.geekbang.org/resource/image/f6/19/f6dee390ea9e5971e31857b18768ef19.jpeg" alt="">

多了一个环节以后，如果口令发生变更，我们只需要重新加密留存的对称密钥就行了，而不需要改动已经加密了的数据。那么，这个使用时间更长的密钥是怎么来的呢？

这就需要我们讨论下一个秘密的来源了：计算机持有的秘密。

## 使用随机数生成对称密钥

计算机持有的秘密，主要用的是我们上一节所讨论的随机数。

由于随机数是不可预测的，我们只要把随机数当做秘密信息来保护，就没有其他的人或者其他的计算机能够知道这个秘密。这样看起来，随机数能够完美地契合对称密钥的需求，无论是长度强度，还是保密要求。

需要一个对称密钥的时候，如果我们知道需要的长度、强度，找对强度匹配的随机数发生器，生成一个对应长度的随机数，就可以获得一个对称密钥了。这是一个看起来很简单、直观的办法。

但是，计算机持有的秘密也有一个缺陷，就是没法转换成我们人脑能够记住的东西。我们没有办法记住随机数，更没有办法记住从随机数衍生出来的对称密钥。既然我们没有办法，解密还需要对称密钥，那就需要计算机替我们记住它。

计算机该怎么管理对称密钥，怎么保守密钥秘密？这些问题也就一下子都冒出来了。

正像我们讨论过的一样，使用口令推导出的密钥可以保护使用时间更长的密钥，当然也包括使用随机数生成的密钥。不过这种保护方式，也有很大的局限性。这种局限性又在哪里呢？还有没有其他的方式？这些问题，我们下一次再讨论。

# Take Away（今日收获）

今天，我们讨论了一个合格的对称密钥应该满足什么条件，以及对称密钥的两个主要来源。

通过今天的讨论，我们要：

- 了解对称密钥要满足的三个条件：长度、强度和秘密。
- 了解产生对称密钥的两个主要办法：使用随机数，或者是基于口令的密钥推导。
- 知道使用基于口令的密钥推导来保护数据的常用办法。

# 思考题

好的，又到了留思考题的时候了。

今天的思考题，我们稍微加大一点难度。不过也不用紧张，我相信只要你去反复撕扯这个问题，不管结论是什么，你都会有收获的。

我们反复强调过，我们能够记住的东西很少，我们能够记住的口令的安全强度也远远不够。那为什么从口令推导出来的密钥就能够更安全呢？ 如果口令只有6位数字，猜中口令的可能性是10^6。

转换成按位表示的安全强度，也不过就是20位的强度。这样的安全强度我们应该担心吗？如果这样的担忧是合理的，我们应该怎么提高口令的安全性？如果使用从口令推导出来的密钥，需要注意哪些问题？

欢迎在留言区留言，分享你的经验。参与讨论的人越多，我们互相学习、互相启发，能够得到的就越多。

好的，今天就这样，我们下次再聊。

元旦快乐！
