Perl 的 srand() 默认种子,发布版本 5.004 的弱点是啥?
Posted
技术标签:
【中文标题】Perl 的 srand() 默认种子,发布版本 5.004 的弱点是啥?【英文标题】:What are the weaknesses of Perl's srand() default seed, post version 5.004?Perl 的 srand() 默认种子,发布版本 5.004 的弱点是什么? 【发布时间】:2012-09-11 21:35:37 【问题描述】:我可以找到大量关于在 Perl 版本 5.004 之前使用 time()
的问题的文档,但没有后续。
对于家庭作业,我们被要求根据默认 Perl srand()
在默认播种中仍然存在缺陷的假设对程序结果进行逆向工程。 changelog for the perl 5.004 release 声明 srand()
默认种子现在基于“大量难以预测的系统相关值”。
是这样吗?如果是的话,这些价值观是什么?它们是否有任何固有的弱点?
【问题讨论】:
perl5.git.perl.org/perl.git/blob/HEAD:/util.c#l5563 看起来像是(现在)的地方。它显然曾经住在 pp.c。 perl5.git.perl.org/perl.git/blob/HEAD:/pp.c#l2700 似乎是这样称呼它,但我并没有假装对此有任何了解。 【参考方案1】:(我不是密码学家,但这些年来我吸收了很多东西。几年前我不得不帮助检查客户的随机数生成,这就是导致发现下面提到的 Crypt::Random 错误的原因。)
如果您正确缩进所有这些 ifdef,则种子代码更有意义。这是5.16.0中的代码。
U32
Perl_seed(pTHX)
dVAR;
/*
* This is really just a quick hack which grabs various garbage
* values. It really should be a real hash algorithm which
* spreads the effect of every input bit onto every output bit,
* if someone who knows about such things would bother to write it.
* Might be a good idea to add that function to CORE as well.
* No numbers below come from careful analysis or anything here,
* except they are primes and SEED_C1 > 1E6 to get a full-width
* value from (tv_sec * SEED_C1 + tv_usec). The multipliers should
* probably be bigger too.
*/
#if RANDBITS > 16
# define SEED_C1 1000003
# define SEED_C4 73819
#else
# define SEED_C1 25747
# define SEED_C4 20639
#endif
#define SEED_C2 3
#define SEED_C3 269
#define SEED_C5 26107
#ifndef PERL_NO_DEV_RANDOM
int fd;
#endif
U32 u;
#ifdef VMS
# include <starlet.h>
/* when[] = (low 32 bits, high 32 bits) of time since epoch
* in 100-ns units, typically incremented ever 10 ms. */
unsigned int when[2];
#else
# ifdef HAS_GETTIMEOFDAY
struct timeval when;
# else
Time_t when;
# endif
#endif
/* This test is an escape hatch, this symbol isn't set by Configure. */
#ifndef PERL_NO_DEV_RANDOM
# ifndef PERL_RANDOM_DEVICE
/* /dev/random isn't used by default because reads from it will block
* if there isn't enough entropy available. You can compile with
* PERL_RANDOM_DEVICE to it if you'd prefer Perl to block until there
* is enough real entropy to fill the seed. */
# define PERL_RANDOM_DEVICE "/dev/urandom"
# endif
fd = PerlLIO_open(PERL_RANDOM_DEVICE, 0);
if (fd != -1)
if (PerlLIO_read(fd, (void*)&u, sizeof u) != sizeof u)
u = 0;
PerlLIO_close(fd);
if (u)
return u;
#endif
#ifdef VMS
_ckvmssts(sys$gettim(when));
u = (U32)SEED_C1 * when[0] + (U32)SEED_C2 * when[1];
#else
# ifdef HAS_GETTIMEOFDAY
PerlProc_gettimeofday(&when,NULL);
u = (U32)SEED_C1 * when.tv_sec + (U32)SEED_C2 * when.tv_usec;
# else
(void)time(&when);
u = (U32)SEED_C1 * when;
# endif
#endif
u += SEED_C3 * (U32)PerlProc_getpid();
u += SEED_C4 * (U32)PTR2UV(PL_stack_sp);
#ifndef PLAN9 /* XXX Plan9 assembler chokes on this; fix needed */
u += SEED_C5 * (U32)PTR2UV(&when);
#endif
return u;
代码如此混乱,因为它实际上是几种不同的获取熵的方法,它们都交错在一起。基本上有两条路径:系统随机设备和从解释器和环境的状态中收集。
系统随机设备。这是最简单也可能是最强的方法。如果您的操作系统有一个不阻塞的随机设备,即。 /dev/urandom
从中读取 32 位。完毕! #ifndef PERL_NO_DEV_RANDOM
(漂亮的双重否定)控制该位。这几乎在每个 Unix 系统上都完成了。此时,Perl 随机种子的分析切换到您特定操作系统的/dev/urandom
的实现。
如果您的系统没有随机设备,基本上是 Windows,Perl 会退回到通过混合一些难以预测的系统值来派生种子。
时间以微秒或几秒为单位,取决于gettimeofday()
是否存在。
进程 ID,PerlProc_getpid()
。
当前堆栈指针的内存位置PTR2UV(PL_stack_sp)
。
它应该用这些信息做什么,这就是一开始的大评论的内容,就是使用真正的散列算法将它们混合在一起。相反,它将它们乘以各种常量(SEED_C1
、SEED_C2
等)并将它们相加。这肯定是有缺陷的。
理论上,所有这些信息都是可预测的。我不知道预测系统信息的最新技术是什么,但是时间 + pid + 堆栈指针是一种相当常见的获取熵的方法,并且肯定会有关于该主题的论文。
Perl 的所有方法都有一个共同的缺陷,即使在 64 位机器上,它也只使用 32 位来完成这一切。它不会从/dev/urandom
中提取 64 位,只有 32 位。即使有 64 位信息,它也只会查看进程 ID、堆栈指针或时间信息的 32 位。
通读代码后我关心三个问题。
它仅使用 32 位随机性。多 GPU 系统可能会暴力破解。
(Unix) 你的/dev/urandom
有多好。
/dev/urandom
如果你太快地从熵中提取太多,可能会耗尽熵。它不会阻塞,而是会产生更弱的熵。这超出了 Perl 的控制,但却是系统范围的弱点。此外,一些程序可能会拉出比它们需要消耗更多的熵/dev/urandom
。我们发现 a bug years ago in Crypt::Random 正在这样做。
除了 32 位问题,这可能是最薄弱的环节。
它使用什么随机函数?一旦提供了种子,它将传递给哪个随机数函数?较差的 rand 函数更容易猜出种子。 Perl 会查找几个,通常以drand48
结尾。您可以查看它的用途:use Config; print $Configrandfunc'
。我不知道它有多好用,但是 OS X drand48 手册页说 random(3)
更强大,而 Linux 手册页说 drand48 is obsolete。
该功能从……天哪,90 年代后期就没有被触及过。它已移至 util.c,但尚未被认真对待。 git blame 132efe8bfb7cd0fb1beb15aaf284e33bf44eb1fa^ pp.c
显示真实历史,寻找S_seed
。它可能需要一些爱。大多数其他语言都有more advanced random number generators。
【讨论】:
以上是关于Perl 的 srand() 默认种子,发布版本 5.004 的弱点是啥?的主要内容,如果未能解决你的问题,请参考以下文章