什么是生成随机数最安全的种子?

70
什么是最安全的熵源来种子随机数生成器?这个问题与语言和平台无关,适用于网络上的任何计算机。理想情况下,我正在寻找云环境中机器可用的来源或由托管公司提供的服务器。

需要记住两个重要的弱点。使用时间发送随机数生成器是CWE-337的违规行为。使用小的种子空间将是CWE-339的违规行为。


19
如果你将 Geiger 计数器连接到电脑上并从中获取信息,那可能是最随机的“常见”可用信息。 - James Black
1
@Neil Butterworth 在随机数生成方面的安全性始终是攻击者难以猜测的值。 - rook
1
@James Black,这在云环境中是无法实现的,而且使用随机数超出了本问题的范围。 - rook
3
@The Rock - 那么服务器没有产生种子吗?没有更多细节,这个问题很难回答,因为任何传递种子的过程都将涉及使用比https更多的加密方式,然后出现密钥管理问题。对于云计算来说尤其如此,因为你必须假定系统管理员是不值得信任的。你可能需要阅读《编程撒旦的计算机》来更好地了解这一点:http://lambda-the-ultimate.org/node/3482 - James Black
2
这两个标准建议使用硬件设备。 - Steven Sudit
显示剩余7条评论
19个回答

93

以下是一些想法。如果你不耐烦,请跳到结论部分。

1. 什么是安全种子?

安全性只相对于攻击模型而言。我们需要一个由n位组成的序列,该序列对于攻击者有n位熵:简而言之,攻击者从可能的2n个值中选择任意一个值的概率都是相等的。

这是一个与攻击者可获得的信息相关的模型。生成和使用种子的应用程序(通常在PRNG中)知道确切的种子;种子是否“安全”并不是种子本身甚至是种子生成过程的绝对属性。重要的是攻击者对生成过程所拥有的信息量。这个信息量因情况而异;例如,在多用户系统上(比如类Unix系统,具有硬件强制应用程序隔离功能),内存访问的精确时间可以揭示关于名义上受保护的进程如何读取内存的信息。即使是远程攻击者也可以获得这样的信息。这已经在AES加密中得到证明(典型的AES实现使用内部表,其访问模式取决于密钥;攻击者通过精确计时服务器响应来强制缓存未命中并检测它们)。

种子的生命周期必须考虑在内。只要攻击者不知道种子,种子就是安全的;这个属性在之后必须仍然成立。特别地,不应该能够从随后PRNG输出的摘录中恢复种子。理想情况下,即使在某个时刻获得完整的PRNG状态,也不应该提供任何关于PRNG之前产生的比特的线索。
我想在这里强调的是,只有在种子可以保持安全的情况下使用,种子才是“安全”的,这或多或少意味着加密安全的PRNG和一些防篡改的存储。如果有这样的存储,则最安全的种子是很久以前生成的那个,在防篡改硬件上托管的安全PRNG中使用过的种子。
不幸的是,这样的硬件很昂贵(称为HSM,成本通常为几百或几千美元),而且通常很难证明其成本合理(一个坏种子不会阻止系统运行;这是安全性无法测试的常见问题)。因此,通常采用“主要是软件”解决方案。由于软件不能提供长期机密存储,种子寿命被任意缩短:定期获取新种子。在Fortuna中,这样的重新播种应该至少每生成一兆字节的伪随机数据进行一次。
总之,在没有HSM的设置中,安全种子是可以相对容易地获得的(因为我们经常这样做),并且使用攻击者无法收集的数据。
2. 混合

随机数据源不会产生漂亮的均匀位(每个位的值恰好为1的概率为0.5,且位值彼此独立)。相反,随机源会产生特定于源的值集。这些值可以编码为位序列,但你得不到你的钱的价值:要拥有n比特的熵,必须具有使用远多于n比特的值进行编码的值。

在这里使用的密码工具是一个PRF,它接受任意长度的输入,并生成一个n比特的输出。这种类型的密码学安全PRF被建模为random oracle:简而言之,在给定输入的情况下,预测有关oracle输出的任何内容都是不可行的。

现在,我们有哈希函数。哈希函数必须满足一些安全属性,即抗预像、第二预像和碰撞。我们通常通过尝试看它们与随机神谕模型的偏差来分析哈希函数。这里有一个重要的点:遵循随机神谕模型的PRF将是一个好的哈希函数,但是可能存在良好的哈希函数(在抵抗预像和碰撞方面),而这些函数仍然容易与随机神谕区分开来。特别地,SHA-2函数(SHA-256、SHA-512等)被认为是安全的,但由于“长度扩展攻击”(给定h(m),可以计算出部分约束消息m'h(m || m')而不知道m),它们与随机神谕模型不同。长度扩展攻击似乎并没有提供任何快捷方式来创建预像或碰撞,但它表明这些哈希函数不是随机神谕。对于SHA-3竞赛,NIST表示候选者不应允许这种“长度扩展”。

因此,混合步骤并不容易。现在最好的选择仍然是使用SHA-256或SHA-512,并在选择SHA-3时切换(这应该会在2012年中期左右发生)。

3. 来源

一台计算机是一个确定性的机器。为了获得一些随机性,您必须混合一些物理世界的测量结果。
哲学注:在某个时候,您必须信任一些聪明的人,这些人可能穿着实验室外套或被付钱进行基础研究。当您使用哈希函数(如SHA-256)时,实际上是相信一群密码学家告诉您:我们努力查找缺陷,并且已经持续几年,但没有发现。当您使用具有盖革计数器的衰变放射性物质时,您正在相信一些物理学家,他们说:我们非常努力地寻找预测下一个原子核将何时爆炸的方法,但我们没有发现。请注意,在这种特定情况下,“物理学家”包括像贝克勒尔,卢瑟福,玻尔或爱因斯坦这样的人,“非常努力”意味着“超过一个世纪的累积研究”,因此在这里您并不处于未知领域。然而,安全仍然存在一些信仰。
一些计算机已经包括可以生成随机数据的硬件(即使用和测量物理过程的硬件,据物理学家所说,足够随机)。 VIA C3(一种x86兼容CPU系列)具有此类硬件。令人惊奇的是,30年前的家用计算机Commodore 64也有硬件RNG(至少Wikipedia如此说)。
除非使用特殊的硬件,否则必须使用任何可能得到的物理事件。通常,您会使用按键、传入的以太网数据包、鼠标移动、硬盘访问等,每个事件都带有一些数据,并在可测量的瞬间发生(现代处理器具有非常准确的时钟,由于循环计数器)。这些瞬间和事件数据内容可以累积为熵源。这对操作系统本身来说要容易得多(它直接访问硬件),而不是对应用程序来说,因此收集种子的正常方式是询问操作系统(在Linux上,这称为/dev/random/dev/urandom [两者都有优点和问题,选择你的毒药];在Windows上,调用CryptGenRandom())。
一个极端情况是1.2版本之前的Java小程序,在添加java.security.SecureRandom之前。由于Java非常有效地将应用程序代码与硬件隔离开来,因此获得随机种子是一个艰巨的挑战。通常的解决方案是同时运行两个或三个线程,并进行疯狂的线程切换,以便每秒线程切换次数有些随机(实际上,这尝试通过操作系统调度程序操作的时间来提取随机性,这取决于在计算机上发生的事件,包括与硬件相关的事件)。这是相当不令人满意的。
与时间相关的措施的一个问题是攻击者也知道当前时间。如果攻击者可以应用程序访问机器,那么他也可以读取循环计数器。

有人提出使用音频卡作为“白噪声”的来源,通过将放大器调到最大(即使服务器现在也有音频)。其他人则主张启动网络摄像头(我们知道网络摄像头的视频是“嘈杂”的,这对于随机性来说很好,即使网络摄像头面对的是一堵墙);但带有网络摄像头的服务器并不常见。您还可以ping一个外部网络服务器(例如www.google.com),看看它返回所需的时间(但这可能会被攻击者窃听网络观察到)。

混合步骤的美妙之处,在于哈希函数只能累积熵;即使数据不太随机,添加数据也没有任何害处。尽可能多地通过哈希函数塞入数据。哈希函数非常快速(一个良好的SHA-512实现将在典型PC上使用单个核心处理超过150 MB/s),并且种子不经常发生。

4. 结论

使用HSM。它们价值几百或几千美元,但你的机密比这更有价值吧?HSM包括RNG硬件,运行PRNG算法,并具有防篡改功能的种子存储。此外,大多数HSM已经获得了各种国家法规的认证(例如美国的FIPS 140和欧洲的EAL级别)。

如果您太过吝啬,不愿购买HSM,或者想要保护实际上并不是很有价值的数据,那么可以使用通过哈希大量物理度量获得的种子来构建一个具有密码学安全性的PRNG。任何来自某些硬件的东西都应该被哈希,以及获取该数据的即时时间(读作“周期计数器”)。在此处应将数据哈希为兆字节。或者,更好的选择是不这样做:只需使用操作系统提供的工具,其中已经包含了这样的代码。

3
+1 这是一篇出色的答案,我学到了很多。我直觉上同意积累熵的概念,但你有什么来源或证明吗?random.c的熵池只有4kb,但它不断添加熵并混合它,这支持了这个论点。 - rook
关于网络摄像头面对墙壁的问题:我听说几年前有一家公司使用带有镜头盖的网络摄像头作为廉价、高质量、高带宽的随机数生成器。但是在谷歌搜索中找不到相关信息。 - LarsH
1
@Rook:熵测量了数据可能具有的值的数量。只有当两个不同的收集值集会导致相同的哈希值(即碰撞)时,熵才会通过哈希而丢失。一个n位输出的哈希函数应该至少抵抗2^(n/2)的工作因素以防止碰撞。如果哈希混合没有积累至少n/2位的熵,则可以将其转化为对哈希函数的碰撞攻击。 - Thomas Pornin
只是澄清一下,工作因素只是生日悖论所强加的限制,对吗? - Steven Sudit
是的,生日悖论意味着对于_任何_哈希函数,无论它有多完美,都可以找到这么多的冲突。因此,我们需要好的哈希函数才能达到“仅仅”那个抵抗水平。 - Thomas Pornin
1
我们是否应该更新这个答案以反映现在一些由英特尔制造的CPU板载具有随机数生成器?顺便说一下,引入英特尔常春藤桥的那个甚至应该是FIPS认证的。对于较小量的随机性,您还可以使用智能卡甚至TPM。 - Maarten Bodewes

52
最安全的种子是熵级别最高的种子(或无法预测的位数最多的种子)。时间通常是一个不好的种子,因为它的熵很小(即,如果你知道交易发生的时间,你可以在几个位内猜出时间戳)。硬件熵源(例如来自衰变过程的熵)非常好,因为它们为每个种子提供一位熵。
通常,硬件源对于大多数需求来说是不切实际的,因此这使您依赖于混合一些低质量的熵源以产生更高的熵。通常,这是通过估计每个样本的熵位数,然后收集足够的样本,使熵源的搜索空间足够大,以至于攻击者无法进行搜索(128位是一个很好的经验法则)。
您可以使用的一些来源是:当前微秒时间(通常具有1/2位非常低的熵,取决于分辨率和攻击者猜测的难度),UI事件的到达时间等等。
操作系统源,如/dev/random和Windows CAPI随机数生成器通常提供这些低熵源的预混合源,例如Windows生成器CryptGenRandom包括:
  • 当前进程ID(GetCurrentProcessID)。
  • 当前线程ID(GetCurrentThreadID)。
  • 自启动以来的滴答计数(GetTickCount)。
  • 当前时间(GetLocalTime)。
  • 各种高精度性能计数器(QueryPerformanceCounter)。-
  • 用户环境块的MD4哈希值,其中包括用户名、计算机名和搜索路径。[...]-
  • 高精度内部CPU计数器,如RDTSC、RDMSR、RDPMC

一些PRNG具有内置策略,允许混合来自低质量来源的熵以产生高质量结果。一个非常好的生成器是Fortuna生成器。它专门使用限制风险的策略,即使任何熵源被攻击也不会有太大的风险。


9
同意,特别是关于将几个小的熵元素组合在一起的建议,比如给女友安装GPS追踪器。(小的熵元素,商场并不算太大。) - Philip Kelley
1
MD4仅用于熵收集,实际生成器基于SHA-1。CryptGenRandom不太可能违反这些CWE类型。我的保守估计是这些源中有>80位的熵,除非攻击者已经入侵了该机器,或者启动时间和随后的活动非常精确地被知道。虽然这并不理想,但对于许多应用程序来说,实际上是安全的。我也不是在建议这是黄金标准的例子,只是一个从低质量源中提取高质量种子的方式的例子。 - Dean Povey
2
@TheRook:你违反了CWE-337(可预测种子)规定,因为你仅使用计时器。CryptGenRandom使用计时器作为种子的来源之一。因此,即使你能够完美地预测计时器,你仍然无法预测使用的种子。因此,CryptGenRandom不违反CWE-337。同样,使用高性能交错计数器自动导致大的种子空间,因此我们也可以确定CWE-339没有被破坏。 - MSalters
2
@Rook:解决方案是非常清楚地说明为什么这个想法是有害的。否则,你只会留下侮辱性的概括,比如“你有问题”。 - Steven Sudit
我把我的-1变成了+1,因为Fortuna太棒了。它的设计非常出色,部分原因在于它有一个熵池,这就是这个问题的答案。享受这个徽章吧。 - rook
显示剩余15条评论

15
最安全的种子是真正随机的一个,您可以通过使用以下方式在当今实际计算系统中进行近似,按照信心程度递减排列:
  • 特殊硬件
  • 操作系统提供的工具尝试捕获磁盘读取和鼠标移动等混沌事件生成的信息 (/dev/random)。在这条“捕捉不可预测事件”的线上,另一种选择是使用一个独立的进程或机器来捕获它作为一个熵池的变化情况,而不是使用由操作系统提供的“安全”的随机数生成器,例如请参见EntropyPool
  • 使用不好的种子(例如时间)并将其与只有您知道的其他数据相结合(例如,使用哈希时间、秘密和一些其他标准(如应用程序/操作系统的PID或内部状态),以便它不一定随时间增加和减少)

9
在数据中心,磁盘读取和鼠标移动(尤其是后者!)往往不如桌面电脑适合作为熵源。请注意,这里的“熵源”指的是计算机用于生成随机数或加密密钥的来源。 - caf
1
通过数据中心网络从 iSCSI 磁盘读取的磁盘将具有足够的熵,因为网络延迟会增加相当多。 - MSalters

8
作为一次性密码的有趣应用,每当我从事间谍活动时,我都有一个系统,只需要传达几个字母。例如,上次我向大芬威克公国出售建造烤面包机的秘密计划时,我只需要低声说:

enonH

给我的同伙。她知道要获取http://is.gd/enonH-(这是一个“安全”的扩展URL,它会带您到is.gd扩展页面,该页面指向完全安全的青蛙图像)。这给了我们409k位的一次性密码,或者如果我在低语“enonH”时眨眼,她知道要获取图像的哈希值,并将其用作我的下一次传输的解码密钥。

由于JPEG图像中的压缩,它们往往是相对较好的熵源,如ent所述:

$ ent frog.jpg
熵 = 7.955028 bits 每字节。

最佳压缩将减少此51092字节文件的大小0%。

51092个样本的卡方分布为4409.15,随机情况下会超过这个值0.01%的时间。

数据字节的算术平均值为129.0884(127.5 =随机)。
Pi的蒙特卡罗值为3.053435115(误差 2.81%)。
串行相关系数为0.052738(完全不相关= 0.0)。

将其与我指导她使用的几乎不可能猜测的图像相结合,我的秘密烤面包机计划就安全地避开了官方的监视。


1
"enonH" 只是一个例子,我没有用它来编码我的烤面包机计划,也不小心忘记了我已经在工作中使用过它。我也不是间谍。我甚至不知道什么是烤面包机。真的。 - msw
1
虽然你使用了is.gd,但你只有大约28位的熵,因为我只需要尝试所有可能的URL(目前约4亿个)即可。远远少于真正的一次性密码! - James

7
在Linux机器上,答案是/dev/random。这非常接近于“真正”的随机数生成器,而/dev/urandom则可以通过PRNG生成,如果熵池耗尽的话。以下引用来自Linux内核的random.c文件。整个文件都有很多注释,非常易懂。代码本身是从PGP采用的,它的美丽不受C语言的限制,由全局结构体包装访问器标记。它是一个简单令人敬畏的设计。
这个例程从设备驱动程序等中收集环境噪声,并返回适用于加密的好的随机数。除了明显的加密用途外,这些数字还适用于种子TCP序列号和其他希望拥有不仅是随机的数字,而且对攻击者难以预测的地方。
操作原理:计算机是非常可预测的设备。因此,在计算机上产生真正的随机数(而不是伪随机数)极其困难,伪随机数可以通过使用算法轻松生成。不幸的是,攻击者很容易猜测伪随机数生成器的序列,并且对于某些应用程序,这是不可接受的。因此,我们必须尝试从计算机环境中收集“环境噪声”,这对于外部攻击者来说必须很难观察,并使用它来生成随机数。在Unix环境中,最好从内核中完成此操作。
环境中的随机性来源包括键盘之间的时间间隔,某些中断的互中断时间以及其他既是(a)非确定性的又是(b)外部观察者难以测量的事件。从这些来源的随机性被添加到“熵池”中,该池使用类似于CRC的函数进行混合。这不是密码学强度,但是假设随机性没有恶意选择,它是足够的,并且它足够快,以至于在每个中断上执行它的开销非常合理。当随机字节被混合到熵池中时,例程保持存储到随机数生成器内部状态中的随机位数的估计值。
当需要随机字节时,它们通过获取“熵池”的内容的SHA哈希来获得。 SHA哈希避免了暴露熵池的内部状态。人们认为从其输出中推导出有关SHA输入的任何有用信息是计算上不可行的。即使可以以某种聪明的方式分析SHA,只要从生成器返回的数据量小于池中固有的熵量,输出数据就是完全不可预测的。因此,该例程在输出随机数时减少其内部估计的熵池中包含多少位“真随机性”。如果此估计值降至零,则该例程仍然可以生成随机数;但是,攻击者(至少在理论上)可能能够从先前的输出推断出生成器的未来输出。这需要成功地对SHA进行密码分析,这被认为是不可行的,但存在一定的可能性。尽管如此,这些数字应该对绝大多数用途有用。

5

编写一个互联网广播客户端,从广播中随机抽取一个样本。有多个电台可以选择和/或回退。


2
开发这个完美的解决方案需要太多工作量,而且该解决方案只能在线使用,消耗大量带宽(同时流式传输许多电台,没有一个电台可以停止工作,因为这会导致随机数产生不准确)。 - Svisstack
我也考虑过这个。不过我在考虑一个真正的数字无线电接收器。 :) - Chris
2
虽然这个答案不完美,但它可以用来为混合物添加更多的熵源。 - Steven Sudit
1
实际上,真正的无线电将是更好的源。一个USB FM接收器只需几美元,您就可以从每个FM站点获取约10 kbps的速率。并非所有位都是随机的 - 攻击者可以监听 - 但噪声位是随机的。只需以4Khz采样率取最低位即可。这可以让您获得500字节/秒,而且全部是不可预测的。 - MSalters
由于任何现实设置都需要多个站点(如果一个站点静默了怎么办?),因此您需要具有编程调谐功能的高级收音机或多个收音机。 - Seva Alekseyev
显示剩余2条评论

4

詹姆斯是正确的。此外,您可以购买硬件来提供随机数据。我不确定在哪里看到它,但我认为我读到一些声卡带有这样的硬件。

您还可以使用像 http://www.random.org/ 这样的网站。


3
如果你深入研究加密理论,就会发现最安全的种子是由混沌事件生成的。在近代历史中,秘密行动一直在使用所谓的"一次性密码本", 这已被证明是不可能破解的。通常这些都是通过分散在荒无人烟的地区的大量大气听音站产生的。大气噪声足够混乱,可以被视为随机的。这种方法的主要问题在于一次性密码本的后勤支持非常重要。
我建议你找到一个足够混沌的事件来提取数据。

1
请记住,即使是自然熵也存在偏差。像线路噪声、原子衰变或类似过程这样的事物并不能保证均匀性。这就是为什么硬件随机数生成器总是包含相当复杂的逻辑来处理这些不均匀性的原因。 - Joey
如果硬件不是问题,使用相机并选择一个随机像素的颜色值(随机像素选择器的种子是时间)。一定会是随机的。尽管真正的随机性在我们的宇宙中不存在。 - user142019
1
通过分散在彼此远离的偏远地区的各种监听站,我相信可以实现足够程度的随机性。无论如何,一旦物理学家们最终摆脱懒惰并定义一个描述已知宇宙的方程系统,随机性将被证明是一种幻觉。@Johannes Rossel - James
@swilliams 当前精确的地理位置、星球、太阳系、银河系和宇宙,这将在追踪她时非常有帮助 :) - user142019
2
@James:它可能是随机的,但它不是均匀的。你需要既有不可预测性又有均匀性。 - Joey
@Johannes:没错,但这有解决方案:http://en.wikipedia.org/wiki/Randomness_extractor - Steven Sudit

3
4 - 由非常随机的骰子掷出选中。 :-)

现在需要6次掷骰子。来源:http://world.std.com/~reinhold/diceware.html - tbc0

2
好的,假设客户需要一个强密码种子,并且您正在使用云计算,这里提供一种解决方案。如果您需要一些硬件随机数生成器,可以在这里查看:

http://en.wikipedia.org/wiki/Hardware_random_number_generator

所以,这假设每个客户端都有一个公钥/私钥对,服务器知道每个客户端的公钥。 要生成密钥,可以使用类似于PGP的方法,在键入时计算按键之间的时间差异,因为这是不可猜测的。
因此,客户端提交一个随机数请求。 服务器使用硬件生成器用公钥加密,然后用服务器的私钥签名。 然后客户端可以验证它来自哪里,然后解密它。
这将确保您可以安全地生成随机数并将其传递回去。
更新:
你最好查看《计算机程序设计艺术》或任何数值方法书籍,或者查看布鲁斯·施奈尔写的东西,比如这些链接: http://www.schneier.com/blog/archives/2006/06/random_number_g.html http://www.cryptosys.net/rng_algorithms.html http://www.schneier.com/blog/archives/2006/06/random_number_g.html http://www.schneier.com/blog/archives/2006/06/random_number_g.html 关于软件中随机数生成的建议,ftp://ftp.rsasecurity.com/pub/pdfs/bull-1.pdf 您还可以考虑让Crypto ++进行生成,或者至少查看Wei Dai是如何做到的,http://www.cryptopp.com/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接