时间:2021-05-02
内核随机数产生器Linux内核实现了一个随机数产生器,从理论上说这个随机数产生器产生的是真随机数。与标准C库中的rand(),srand()产生的伪随机数不同,尽管伪随机数带有一定的随机特征,但这些数字序列并非统计意义上的随机数。也就是说它们是可重现的--只要每次使用相同的seed值,就能得到相同的伪随机数列。通常通过使用time()的返回值来改变seed,以此得到不同的伪随机数序列,但time()返回值的结果并不是不确定的(可预测),也就是这里仍然缺少一个不确定的噪声源。对于需要真随机数的程序,都不能允许使用伪随机数。为了获得真正意义上的随机数,需要一个外部的噪声源。Linux内核找到了一个完美的噪声源产生者--就是使用计算机的人。我们在使用计算机时敲击键盘的时间间隔,移动鼠标的距离与间隔,特定中断的时间间隔等等,这些对于计算机来讲都是属于非确定的和不可预测的。虽然计算机本身的行为完全由编程所控制,但人对外设硬件的操作具有很大的不确定性,而这些不确定性可以通过驱动程序中注册的中断处理例程(ISR)获取。内核根据这些非确定性 的设备事件维护着一个熵池,池中的数据是完全随机的。当有新的设备事件到来,内核会估计新加入的数据的随机性,当我们从熵池中取出数据时,内核会减少熵的估计值。12345678910111213141516171819202122asmlinkage inthandle_IRQ_event(unsigned intirq, structpt_regs *regs, structirqaction *action){intstatus = 1;intretval = 0;if(!(action->flags & SA_INTERRUPT))local_irq_enable();do{status |= action->flags;retval |= action->handler(irq, action->dev_id, regs);action = action->next;}while(action);if(status & SA_SAMPLE_RANDOM)add_interrupt_randomness(irq);local_irq_disable();returnretval;}上面这段代码是x86上用来处理某条中断线上注册的ISR例程的函数。这里我们感兴趣的地方是:如果ISR在注册期间指定了SA_SAMPLE_RANDOM标志,在处理完action后,还要调用add_interrupt_randomness()这个函数,它使用中断间隔时间为内核随机数产生器产生熵。内核就是在这里为熵池填充新数据的。如果我们完全不操作计算机会如何呢?也就是作为噪声源的产生者,我们完全不去碰键盘,鼠标等外设,不让熵池获得新的数据,这个时候如果去熵池取数据内核会如何反应?内核在每次从熵池中取数据后都会减少熵的估计值,如果熵估计值等于0了,内核此时可以拒绝用户对随机数的请求操作。获取内核随机数有两种方法可以从熵池中获取内核随机数。一种是通过内核导出的随机数接口,另一种是通过特殊的设备文件/dev/random和/dev/urandom。下面分别讨论两种方法。熵的输出接口1voidget_random_bytes(void*buf, intnbytes)该函数返回长度为nbytes字节的缓冲区buf,无论熵估计是否为0都将返回数据。使用这个函数时需要在内核空间。我们写一个小模块来测试一下。123456789101112131415161718192021222324252627282930#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#define NUM 10voidget_random_bytes(void*buf, intnbytes);staticintget_random_number(void){unsigned longrandNum;inti = 0;printk(KERN_ALERT "Get some real random number.\n");for(i=0; i<NUM; i++){get_random_bytes(&randNum, sizeof(unsigned long));printk(KERN_ALERT "We get random number: %ld\n", randNum);}return0;}staticvoidrandom_exit(void){printk(KERN_ALERT "quit get_random_num.\n");}module_init(get_random_number);module_exit(random_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Test");Makefile如下:12345678910obj-m = get_random_num.oKDIR = $(shell uname -r)PWD = $(shell pwd)all:make -C /lib/modules/$(KDIR)/build M=$(PWD) modulesclean:make -C /lib/modules/$(KDIR)/build M=$(PWD) clean#end#编译之后加载模块,通过dmesg命令输出系统log最新的信息,可以看到我们的小模块输出了10个从内核熵池中得到的随机数。卸载模块后再次加载可以重新获取新的随机数,观察输出结果,与之前得到的随机数完全不一样。1234567891011121314151617181920212223 Get some real random number. We get random number: -82199505 We get random number: -276237802 We get random number: 411869317 We get random number: 1779353222 We get random number: 823507551 We get random number: 1061461415 We get random number: 1372137935 We get random number: 1460835009 We get random number: 2002191729 We get random number: -272204344 quit get_random_num. Get some real random number. We get random number: 1111808207 We get random number: -13789055 We get random number: 240443446 We get random number: -606998911 We get random number: 538794850 We get random number: -500786675 We get random number: -1240394927 We get random number: 1233931345 We get random number: 1488497117 We get random number: -177688514/dev/random & /dev/urandom这两个特殊设备都是字符型设备。我们可以在用户空间通过read系统调用读这两个设备文件以此获取随机数。这两个设备文件的区别在于:如果内核熵池的估计值为0时,/dev/random将被阻塞,而/dev/urandom不会有这个限制。123456789101112131415161718192021222324252627282930313233343536373839#include <assert.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>#include <unistd.h>intrandom_number(intmin, intmax){staticintdev_random_fd = -1;char*next_random_byte;intbytes_to_read;unsigned random_value;assert(max > min);if(dev_random_fd == -1){dev_random_fd = open("/dev/random", O_RDONLY);assert(dev_random_fd != -1);}next_random_byte = (char*)&random_value;bytes_to_read = sizeof(random_value);/* 因为是从/dev/random中读取,read可能会被阻塞,一次读取可能只能得到一个字节,* 循环是为了让我们读取足够的字节数来填充random_value.*/do{intbytes_read;bytes_read = read(dev_random_fd, next_random_byte, bytes_to_read);bytes_to_read -= bytes_read;next_random_byte += bytes_read;}while(bytes_to_read > 0);returnmin + (random_value % (max - min + 1));}同样,还可以用dd命令从/dev/urandom中获取指定字节数的随机值并写入文件中保存--如果你需要以文件的形式提供随机数的话。dd if=/dev/urandom of = file count = 1 bs = bytes关于内核随机数产生器的详细介绍,可参考Linux内核设计与实现第二版附录B。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
1.random库的使用:random库是使用随机数的Python标准库从概率论角度来说,随机数是随机产生的数据(比如抛硬币),但时计算机是不可能产生随机值,真
曾经做过一个从数据库中随机抽取记录的程序,在其中用到了随机数编程,下面把ASP中随机抽取随机数的程序写下来供大家参考。关于随机数,请参看以下资料:Rnd函数描述
取随机数命令操作系统支持:Windows、Linux所属类别:算术运算返回一个指定范围内的随机数值。在使用本命令取一系列的随机数之前,应该先使用“置随机数种子”
Rand()函数是系统自带的获取随机数的函数,可以直接运行selectrand()获取0~1之间的float型的数字。如果想要获取0~100之间的整数随机数,可
创建随机数的方法:复制代码代码如下:1~~~~/dev/urandom在Linux中有一个设备/dev/urandom是用来产生随机数序列的。利用该设备我们可以