不少库例程产生的“随机”数是准备用于仿真、游戏等等;它们在被用于密钥生成一类的安全函数时是不够随机的。其问题在于这些库例程使用的算法的将来值能够被攻击者轻易地推导出来(虽然看起来它们多是随机的)。对于安全函数,须要的随机值应该是基于量子效应之类的确实没法预测的值。Linux内核(1.3.30以上)包括了一个随机数发生器/dev/random,对于不少安全目的是足够的。
/dev/random 是如何建立随机数的呢?
Linux 操做系统提供本质上随机(或者至少具备强烈随机性的部件)的库数据。这些数据一般来自于设备驱动程序。例如,键盘驱动程序收集两个按键之间时间的信息,而后将这个环境噪声填入随机数发生器库。
随机数据存储在 熵池中,它在每次有新数据进入时进行“搅拌”。这种搅拌其实是一种数学转换,帮助提升随机性。当数据添加到熵池中后,系统估计得到了多少真正随机位。
测定随机性的总量是很重要的。问题是某些量每每比起先考虑时看上去的随机性小。例如,添加表示自从上次按键盘以来秒数的 32 位数实际上并无提供新的 32 位随机信息,由于大多数按键都是很接近的。
从 /dev/random 中读取字节后,熵池就使用 MD5 算法进行密码散列,该散列中的各个字节被转换成数字,而后返回。
若是在熵池中没有可用的随机性位, /dev/random 在池中有足够的随机性以前等待,不返回结果。这意味着若是使用 /dev/random 来产生许多随机数,就会发现它太慢了,不够实用。咱们常常看到 /dev/random 生成几十字节的数据,而后在许多秒内都不产生结果。
幸运的是有熵池的另外一个接口能够绕过这个限制:/dev/urandom。即便熵池中没有随机性可用,这个替代设备也老是返回随机数。若是您取出许多数而不给熵池足够的时间从新充满,就不再能得到各类来源的合用熵的好处了;但您仍能够从熵池的 MD5 散列中得到很是好的随机数!这种方式的问题是,若是有任何人破解了 MD5 算法,并经过查看输出了解到有关散列输入的信息,那么您的数就会马上变得彻底可预料。大多数专家都认为这种分析从计算角度来说是不可行的。然而,仍然认为 /dev/urandom 比 /dev/random 要“不安全一些”(并一般值得怀疑)。
应用中出现的问题:
在咱们的服务器程序中,用户登录的时候会读取/dev/random产生随机数,问题来了,当用户登录比较密集,这时候read就会返回特别慢,而且返回的字节数也比要求的少,甚至不返回――阻塞。咱们把用户登录处理函数放在了线程池里,致使的问题就是线程池里全部线程均可能会阻塞,这就形成了拒绝服务攻击。致使其余用户登录失败。
解决方案:算法
CODE:安全 1 #include <stdio.h> |
13行: 定义fd为静态变量,这样只打开一次设备。
17 – 19行: 无阻塞模式打开/dev/random设备。若是该设备打开失败尝试打开/dev/urandom。
29行: void get_random_bytes(void* buf, int nbytes)函数是提供给用户的接口,用户调用这个函数就能够获得随机数。
37-57行: read有可能返回的字节数小于请求的字节数。这时候就循环读直到读够了所请求的大小。这样最多重复8次。而后返回。
59-67行: 若是上面重复8次都没有读够所请求的字节数,则咱们本身生成随机数来填充。
注意:打开的fd咱们并无关闭,请您根据本身需求在合适的地方关闭。dom