在这个问题中有一个(常见的)误解,即存在“真正的”随机性,这对安全性很重要。事实上,是否存在“真正的”随机性是一个哲学问题(物理学给出了部分答案),与安全性无关。
随机性有很多概念。与安全相关的是不可预测性。安全性被定义为防范对手。出于安全目的,如果您的对手无法找到或猜到它,则该值是“随机的”。
在安全的上下文中,“真正的随机”有时用来表示一个值是基于某个对手无法复制的物理过程。例如,从这个意义上说,掷硬币通常是真正随机的。但如果硬币偏差过大,并且对手可以看到硬币翻转的结果,则不会。在摄像机前进行 128 次抛硬币不会给你一个安全的 128 位随机数。(它确实为您提供了一个无法提前预测的值,这对某些事情有利但不利,例如,作为加密密钥。)
相反,只要攻击者无法学习随机生成器的种子或内部状态,由密码安全伪随机生成器(CSPRNG)以确定性方式计算的值作为随机值是完全可以的。除了种子的生成之外,仅涉及确定性物理过程,并且相同的种子被用于生成其他随机值,这一事实不会损害随机值的安全性(假设 CSPRNG 被正确设计和实施 -适用于任何安全处理的假设)。
“真正的”随机性对于安全性是必要的,因为您必须以某种方式播种 CSPRNG。您可以使用 CSPRNG 的输出为 CSPRNG 播种,但最终,您必须从一个不确定的或未充分精确建模的物理过程开始。
只有当它足够不可预测时,随机值才足够好。12729af5a51075a68db9d4b05ce7981a
如果我告诉你我在和之间随机选择了我的密钥fc42099f25ee1eb5a8dc1178c35868b8
,那对我不利:事实上我确实随机生成了这两个值,你不知道它是哪一个,但你仍然可以在最多两个猜测。值的不可预测性或未知性的度量称为熵(请注意,有许多相关但不同的概念称为熵)。一个完全已知的值的熵为 0。一个具有相同机会成为两种已知可能性之一的值的熵为 1。通过告诉您我的密钥是这两个值之一,我已将其熵减少到 at大多数 1 位,无论这两个值是如何随机生成的。
一个音频文件可能有也可能没有大量的熵。在一种极端情况下,如果对手拥有相同的文件,则熵为 0。如果对手有相同声音的不同录音,由于麦克风质量和位置可能会出现伪影,但音频压缩往往会消除这些伪影. 麦克风白噪声可能是一个不错的熵源,但您应该直接从硬件中获取它:当您获得录音时,很难确保噪声已被保留并且相同的噪声未被复制别的地方。
大多数编程语言的标准库中的函数的问题rand()
不在于它们是伪随机的,而是它们在密码学上不安全,主要有两个原因:
- 对手可以找到种子。例如
srand(time())
,大多数情况下是可预测的(取决于对手知道您的应用程序何时运行的精确程度——这与时间周期无关)。即使对手不知道种子,如果种子是一个 32 位的数字,对手很容易通过蛮力尝试所有可能的种子。如果它是一个 64 位数字,它的成本很高,但仍然可行。
- 输出不是独立的:给定足够的输出
rand()
,可以计算其他输出。
安全随机生成器,例如/dev/urandom
or CryptGenRandom
,没有这些缺陷:它们使用来自安全种子(在现代计算机中,可以从主 CPU 中的组件生成)的 CSPRNG 算法(保证独立输出)。