L016使用/dev/random生成随机数

很多库例程产生的“随机”数是准备用于仿真、游戏等等;它们在被用于密钥生成一类的安全函数时是不够随机的。其问题在于这些库例程使用的算法的未来值可以被攻击者轻易地推导出来(虽然看起来它们可能是随机的)。对于安全函数,需要的随机值应该是基于量子效应之类的确实无法预测的值。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>
 2 #include <string.h>
 3 #include <sys/types.h>
 4 #include <sys/stat.h>
 5 #include <sys/file.h>
 6 #include <sys/time.h>
 7 #include <errno.h>
 8 #include <unistd.h>
 9 #include <stdlib.h>
 10

 11 static int get_random_fd (void)
 12 {
 13     static int fd = -2;
 14
 15     if (fd == -2)
 16     {
 17         fd = open ("/dev/random", O_RDONLY | O_NONBLOCK);
 18         if (fd == -1)
 19         fd = open ("/dev/urandom", O_RDONLY | O_NONBLOCK);
 20     }
 21
 22     return fd;
 23 }
 24
 25 /*
 26 * Generate a series of random bytes. Use /dev/random if possible,
 27 * and if not, use /dev/urandom.
 28 */
 29 void get_random_bytes(void* buf, int nbytes)
 30 {
 31 int i, fd = get_random_fd();
 32 int lose_counter = 0;
 33 char cp = (char)buf;
 34 struct timeval tv;
 35 static unsigned seed = 0;
 36
 37 if (fd >= 0)
 38 {
 39 while (nbytes > 0)
 40 {
 41 i = read (fd, cp, nbytes);
 42 if ((i < 0) &&
 43 ((errno == EINTR) || (errno == EAGAIN)))
 44 continue;
 45
 46 if (i <= 0)
 47 {
 48 if (lose_counter++ == 8)
 49 break;
 50
 51 continue;
 52 }
 53 nbytes -= i;
 54 cp += i;
 55 lose_counter = 0;
 56 }
 57 }
 58
 59 for (i = 0; i < nbytes; i++)
 60 {
 61 if (seed == 0)
 62 {
 63 gettimeofday(&tv, 0);
 64 seed = (getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec;
 65 }
 66 *cp++ = rand_r(&seed) & 0xFF;
 67 }
 68
 69 return;
 70 }

解决方案:

1--3行:  定义fd为静态变量,这样只打开一次设备。
  17 – 19行: 无阻塞模式打开/dev/random设备。如果该设备打开失败尝试打开/dev/urandom。
  29行:  void get_random_bytes(void* buf, int nbytes)函数是提供给用户的接口,用户调用这个函数就可以得到随机数。
  37-57行: read有可能返回的字节数小于请求的字节数。这时候就循环读直到读够了所请求的大小。这样最多重复8次。然后返回。
  59-67行: 如果上面重复8次都没有读够所请求的字节数,则我们自己生成随机数来填充。
  注意:打开的fd我们并没有关闭,请您根据自己需求在合适的地方关闭。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容