我能否通过结合random_device和mt19937并重新播种来生成密码学安全的随机数据?

7
我需要在c++11中生成加密安全的随机数据,我担心对于所有数据使用random_device会严重限制性能(参见Stephan T. Lavavej的 "rand() Considered Harmful" 第23页,他说在他的系统上测试时,random_device是1.93 MB/s,而mt19937是499 MB/s),因为此代码将在移动设备(Android通过JNI和iOS)上运行,这些设备可能比上述数字慢。
此外,我知道mt19937不是加密安全的,来自wikipedia:“观察足够数量的迭代(在MT19937的情况下为624,因为这是从中产生未来迭代的状态向量的大小)允许预测所有未来的迭代”。
考虑到上述所有信息,我是否可以通过每624次mt19937迭代从random_device生成新的随机种子来生成密码学安全的随机数据?或者更好的是,每X次迭代生成新的随机种子,其中X是从1到624之间的随机数(来自random_device或由random_device或mt19937生成的种子)?

2
“random_device”甚至不需要是非确定性的,所以我认为这不是一个很好的想法。如果您真的需要非确定性数据,则使用操作系统提供的任何加密API可能是正确的方法。 - Praetorian
在iOS上,LLVM使用/dev/urandom作为其源,根据此(第7页),它保证是密码学安全的。 在Android上,gcc使用/dev/random或/dev/urandom作为其源,因此我可以选择使用OpenSSl和其他人使用的“/dev/random”进行初始化,并保证(在Android的能力范围内)它是非确定性的。 - Avi Poss
3
如果您预先知道random_device的来源适用于用作CSPRNG,那么这显然是一个合适的选择。但我仍然对您的mt19937想法持谨慎态度。在加密方面,一个简单的规则应该是,除非您是该领域的专家,否则总是优先选择现有的经过验证的解决方案,而不是做一些看似聪明的事情。您搞砸的可能性比想出真正新颖的想法要大得多。您测试过自己的想法的吞吐量吗?mt19937具有19937位状态,因此频繁重新生成种子可能并不比random_device表现更好。 - Praetorian
2个回答

7
不要这样做。说真的,千万别这么做。这不只是在自找麻烦——这更像是在最危险的城市里进入最犯罪的地带,还携带了很多贵重物品。
相比于尝试重新播种MT 19937以足够覆盖其不安全性,我建议通过在计数器模式下运行AES来生成您的随机数。这需要您获得一个(但仅有一个)正确大小的好随机数,用作生成器的初始“种子”。
您将其用作AES的密钥,简单地使用它来加密连续数字以获得看起来随机但易于再现的输出流。
这有很多优点。首先,它使用的算法经过了大量研究,并且通常被认为非常安全。其次,它意味着您只需要分发一个(相当小的)随机数作为整个系统的“密钥”。第三,它可能提供更好的吞吐量。Intel和(看起来是)独立测试都显示出吞吐量范围,从低端开始与MT 19937相媲美,到高端快4-5倍左右。考虑到您的使用方式,我预计您会获得接近(甚至可能超过1)他们展示的范围顶端的结果。

底线:在计数模式下,AES显然是解决当前问题的更好方案。您所能期望的最好情况是,MT 19937最终变得与其速度和安全性相当。实际上,它可能会让这两种希望都落空,并且变得更慢并且安全性明显较差。


1. 它如何超越这些结果?毫无疑问,这些结果是基于加密大量数据的——即从RAM中读取一块数据,对其进行加密,然后将结果写回RAM。在您的情况下,您不需要从RAM中读取结果——您只需在CPU中生成连续的数字,对其进行加密,并写出结果。


6
简短的回答是,不行。加密安全 RNG 的要求非常严格,如果您在这里提出这个问题,那么您对这些要求的了解还不够。如 Jerry 所说,如果您需要可重复性,则 AES-CTR 是一种选择。另一个选择是,在您的系统中寻找 Yarrow 或 Fortuna 的实现,但这种方法不允许重复使用。通常情况下,最好在库中找到 CSRNG,而不是自己编写。库编写者已经足够了解良好 CSRNG 的要求。

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