混合熵源的安全性

4
假设我们正在生成非常大的数字(例如128位或256位)作为块密码的密钥。
进一步假设我们戴着锡纸帽子(至少在外面的时候)。
由于如此偏执,我们想要确保我们有足够的熵,但我们并不完全信任任何特定的来源。也许政府正在操纵我们的硬币。也许这些骰子微微有些重量不均。如果输入到/dev/random的硬件中断有点太一致会怎么样?(除了偏执之外,我们还很懒,不想全部手动生成...)
那么,让我们把它们混合在一起。
哪些安全方法可以做到这一点?假设仅仅连接每个来源的几个字节并不完全安全-如果其中一个来源存在偏差,它可能在理论上容易受到相关密钥攻击等问题。
运行SHA-256是否足够?
(是的,很快我会拿起《加密工程》的副本。 :))

当我们戴着锡帽时:SHA只是一种加密方案,NSA拥有密钥。 - cobbal
@cobbal 虽然有点好笑,但显然不正确,因为任何哈希方案都有固定的输出大小,所以它不可能是一个“加密”方案,因为不可能把所有东西都拿回来。此外,你会让人们混淆哈希和加密,这并不理想 :) 对于没有幽默感的道歉。 - Noon Silk
拿到最随机的源代码,然后将其与你能够获取到的最精确的时间表示进行异或运算——听起来对我来说不错(一个非密码学家... :))。 - Will A
@cobbal:在我不相信SHA或其他已知的哈希算法的时候,我也不应该信任任何其他的加密算法。虽然我不是密码学家,但我觉得熵的生成常常是真正的弱点。即使许多“失效”的算法在实践中也足够好,需要例如荒谬数量的选择性明文,但差劲的熵生成甚至可以破坏最安全的算法。 - Nicholas Knight
我建议,尽可能从“不良来源”收集尽可能多的熵 - 例如当前时间戳、进程ID、自上次重启以来的时间、自进程启动以来的CPU时间使用情况、当前对象的内存地址等。然后将所有这些放入std::seed_seq,并与std::random_device中的一些字节(希望是真正随机的)一起放入,然后将该std::seed_seq提供给您喜爱的随机数生成器。 - undefined
4个回答

5
由于您提到了/dev/random,至少在Linux上,/dev/random是通过一个算法来获取熵源的,这个算法非常类似于您所描述的。它使用多种不同可信度的熵源,并将它们混合到一个“熵池”中,使用多项式函数进行混合 - 对于每个新的熵字节,它都会被异或到熵池中,然后整个熵池使用混合函数进行搅动。当需要从熵池中获取一些随机性时,整个熵池将使用SHA-1进行哈希处理以获取输出,然后再次混合熵池(实际上还有一些更多的哈希、折叠和变形操作,以确保反转过程与反转SHA-1几乎同样困难)。同时,还有一堆账务工作正在进行 - 每次向熵池中添加一些熵时,将估计其价值的熵位数添加到账户中,每次从熵池中提取一些字节时,该数字将被减去,如果账户将要降至零以下,则随机设备将阻塞(等待更多外部熵)。当然,如果使用“urandom”设备,则不会发生阻塞,熵池将继续被哈希和混合以产生更多字节,这将使其成为PRNG而不是RNG。

总之...这实际上非常有趣,也非常好注释 - 您可能需要学习它。在linux-2.6树中的drivers/char/random.c


4

我以前做过这个,我的方法就是将它们逐字节进行异或。

运行它们通过其他算法,比如SHA-256,效率非常低下,因此不实用,而且我认为这可能没有什么用处,甚至有害。

如果你确实非常偏执,并且有一点点钱,那么购买一个“真正的”(取决于你对量子力学的信服程度)量子随机数生成器可能会很有趣。

-- 编辑:

顺便说一句,我认为我上面描述的方法(或类似的方法)从任一源的角度来看都是有效的一次性密码,假设其中一个是随机的,因此在它们是独立的并且想攻击你的情况下是无法攻破的。如果有人对此提出异议,我很乐意接受纠正,我也鼓励任何不反对它的人去质疑它,自己找出答案。


虽然我同意这种方法可能是最安全的,但你的方法需要从每个源生成_n_位来生成一个_n_位的密钥,对吗?你能解释一下SHA-256为什么会“非常低效”吗?密钥生成只需要进行一次(或者至少很少),所以效率并不是问题。如果你能提供一些有关通过哈希创建密钥可能造成的危害的信息,那就更好了... - Nicholas Knight
2
尼古拉斯:对威胁进行建模。考虑到哈希是一种确定性函数,那么你希望它能实现什么?从谁那里隐藏什么?如果只是为了生成密钥,那么你的问题就在于密钥存储。如果有人仍然可以看到它,那么哈希密钥并没有任何区别,对吧?关于第一个问题,我没有注意到这是用于密钥生成,那么是的,性能不是问题,因为我想你会经常这样做,而且是的,它需要来自两个源的相同位数(但你肯定希望如此,否则你就有了更高“风险”的数据组件)。 - Noon Silk
@Nicholas:但是哈希是完全确定性的。(嗯,我想我假设你正在哈希大小等于或小于哈希输出大小的数据)。如果您的输入大小大于哈希输出,则其价值有争议。我不知道任何关于这个问题的想法,我可以合法地讨论。我确实看到在收集1kb的密钥数据然后将其转换为256位密钥方面有价值。所以,如果这是您的计划,并且您打算通过哈希来执行此操作,我支持它。 - Noon Silk
2
如果您有偏执症,请记住,如果您使用这种方法,一个聪明的攻击者控制您的其中一个来源,可能会使其复制您的其他源,从而使组合的RNG返回零。 - Rasmus Faber
1
异或并不是一个很好的做法。大多数时候它看起来很酷,但如果你的源之间存在相关性,那么它会被放大。这意味着异或可以缩小搜索空间。我喜欢SHA1,我知道它比异或慢,但它有效。 - Sheena
显示剩余2条评论

4
使用哈希函数是一个好的方法-只需确保低估每个来源贡献的熵量,这样如果您正确地判断其中一个或多个不是完全随机的话,就不会过度削弱您的密钥。
这与key stretching中使用的方法并没有太大区别(尽管在此处您不需要进行多次迭代)。

1
如果您有一个随机源,但不确定它是否偏倚,则有许多不同的算法。根据您想要做的工作量,从原始源浪费的熵也不同。
最简单的算法是(改进的)van Neumann算法。您可以在此pdf中找到详细信息: http://security1.win.tue.nl/~bskoric/physsec/files/PhysSec_LectureNotes.pdf 第27页。
我还建议您阅读此文档,如果您对如何从给定的源产生均匀随机数、真随机数生成器的工作原理等感兴趣!

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