用于密码学的快速伪随机数生成器(C语言实现)

10

我曾使用下面的代码生成用于加密目的的伪随机数序列,但后来我在某个地方读到它可能不是很安全。有人能给我一个更好的生成器的C实现吗?主要目标是让这种方法速度更快。例如,我进行了一些研究,发现Blum Blum Shub方法会通过执行pow(N)计算完全降低性能。

PS.请不要引用没有C/C++代码的维基百科文章。我正在寻找所示内容的C或C++代码示例。

#define ROL(v, shift) ((((v) >> ((sizeof(v) * 8) - (shift))) | ((v) << (shift))))

ULONGLONG uiPSN = doSeed();   //64-bit unsigned integer

for(int i = 0; i < sizeOfArray; i++)
{
    uiPSN = uiPSN * 214013L + 2531011L;
    uiPSN = ROL(uiPSN, 16);

    //Apply 'uiPSN'
}

8
正如维基百科页面所述,梅森旋转算法不适合用于加密目的。 - user395760
6
永远不要试图发明自己的密码学,因为世界上只有两种程序员:一种是无需被告知此事的人,而另一种是即使被告知也不会听取建议的人。 - Nemo
4
普通的随机数生成器不能用于密码学应用。即使是拥有出色统计特性的生成器,也无法抵御比聪明的孩子更复杂的攻击者。密码学随机数生成器则是一种特殊的工具。尽管@delnan是正确的,我仍然担心你打算如何使用这些伪随机数。密码学的第一规则是使用其他人的设计,第二规则是使用其他人的实现。 - Nemo
4
认为自己可以违反这些规则的人数约为实际可以的人数的100倍。除非你已将其成为职业,否则你几乎肯定没有资格设计或实现加密代码。看看OpenSSL中的10个最新漏洞。如果你能说服自己你不会犯任何一个错误,那太棒了。如果不能,为了你自己和你的用户,请“使用其他人的代码”。 - Nemo
3
作为密码学专家,请查找一款经过认证的现成库。 - PurpleAlien
显示剩余16条评论
4个回答

18

ISAAC(http://www.burtleburtle.net/bob/rand/isaacafa.html)可能是最快的加密安全 PRNG 之一(网站上有代码)。另一种方法是使用计数器模式下的块密码。像 TwoFish 这样相对较快且免费提供的密码,在此情境下将是有效的选择。

如果你不需要大量数字,所有现代操作系统都自带适用于密码学用途的 RNG。尽管它们通常不能产生大量数字,因为它们依赖于从输入时间等源积累熵。类 Unix 系统(如 Linux、OSX)拥有 /dev/random,Windows 则有 CryptGenRandom。即使这些不适合你的需求,你也应该使用它们来播种你最终使用的 PRNG。


现在还需要考虑Cha-cha。 - Lee Daniel Crocker

6

看(或使用)OpenSSL库中的随机数生成器。

任何安全随机数生成器的难点都在于种子生成。如果你在Windows上,考虑使用rand_s()。在Linux上可以查看/dev/urand。

有些种子生成方法在重启后不久就变得不太随机。您可以制作一个包含随机字节的文件,并使用该文件和操作系统方法进行种子生成。定期使用随机数生成器编写一个新文件。


1
不要自己编写加密算法,使用经过认证的库。为了提高速度,可以尝试使用能够在 GPU 上运行的库,因为 GPU 具有更强大的计算能力。

-5
我建议使用Mersenne-Twister,我一再使用过。
C代码在这里
如果您使用C++11,则可以将mersenne twister作为库的一部分。 Mersenne Twister目前是最好的算法之一。
以下是我如何在C++11中实现函数。它非常简单明了。mt19937是C++11中内置的Mersenne Twister。
 std::vector<double> classname::mersennetwister(const int& My,const int& Mz,const int& Ny,const int& Nz)
{
int ysize = (My + 2*Ny + 1);
int zsize = (Mz + 2*Nz + 1);
int matsize = ysize*zsize;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::mt19937_64 generator (seed);
std::uniform_real_distribution<double> distribution(0,1);
std::vector<double> randarray = f.array1dgen(matsize,0);
for (int i=0;i<matsize;++i)
{
   randarray[i] = distribution(generator);
}
return(randarray);
}

3
维基百科有关机器翻译的缺点:“原始形式的算法不适用于密码学(不像Blum Blum Shub)。观察足够数量的迭代(在MT19937的情况下为624,因为这是生成未来迭代的状态向量的大小)可以预测所有未来的迭代。” - user395760
1
@awashburn 如果他没问题,那显然很好。但是如果这个(常常不合理的)假设不成立,你不能仅仅假设并推荐一个有缺陷的解决方案。 - user395760
1
如果你所说的“something like”是指“一个CSPRNG”,那么是的,根据定义,这就是你需要的。 - user395760
4
MT 不具有密码学安全性。 - Lee Daniel Crocker
1
你不应该仅使用时间来种子化 PRNG。加密 PRNG 应该使用具有良好熵值的随机值进行种子化,例如来自真正的随机源。 - Maciej S
显示剩余2条评论

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