内核随机数发生器
Linux内核完成了一个随机数发生器,从理论上说这个随机数发生器发生的是真随机数。与规范C库中的rand(),srand()发生的伪随机数不同,尽管伪随机数带有必定的随机特征,但这些数字序列并非核算意义上的随机数。也便是说它们是可重现的–只需每次运用相同的seed值,就能得到相同的伪随机数列。一般经过运用time()的回来值来改动seed,以此得到不同的伪随机数序列,但time()回来值的成果并不是不确认的(可猜测),也便是这儿依然短少一个不确认的噪声源。关于需求真随机数的程序,都不能答应运用伪随机数。
为了取得真实意义上的随机数,需求一个外部的噪声源。Linux内核找到了一个完美的噪声源发生者–便是运用核算机的人。咱们在运用核算机时敲击键盘的时刻距离,移动鼠标的距离与距离,特定中止的时刻距离等等,这些关于核算机来讲都是归于非确认的和不行猜测的。尽管核算机自身的行为彻底由编程所操控,但人对外设硬件的操作具有很大的不确认性,而这些不确认性能够经过驱动程序中注册的中止处理例程(ISR)获取。内核依据这些非确认性的设备事情维护着一个熵池,池中的数据是彻底随机的。当有新的设备事情到来,内核会估量新参加的数据的随机性,当咱们从熵池中取出数据时,内核会削减熵的估量值。
asmlinkage int handle_IRQ_EVEnt(unsigned int irq, struct pt_regs *regs,
struct irqaction *action)
{
int status = 1;
int retval = 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();
return retval;
}
上面这段代码是x86上用来处理某条中止线上注册的ISR例程的函数。这儿咱们感兴趣的当地是:假如ISR在注册期间指定了 SA_SAMPLE_RANDOM标志,在处理完action后,还要调用add_interrupt_randomness()这个函数,它运用中止距离时刻为内核随机数发生器发生熵。内核便是在这儿为熵池填充新数据的。
假如咱们彻底不操作核算时机怎么呢?也便是作为噪声源的发生者,咱们彻底不去碰键盘,鼠标等外设,不让熵池取得新的数据,这个时分假如去熵池取数据内核会怎么反响?
内核在每次从熵池中取数据后都会削减熵的估量值,假如熵估量值等于0了,内核此刻能够回绝用户对随机数的恳求操作。
获取内核随机数
有两种办法能够从熵池中获取内核随机数。一种是经过内核导出的随机数接口,另一种是经过特别的设备文件/dev/random和/dev/urandom。下面别离评论两种办法。
熵的输出接口
?
1 void get_random_bytes(void *buf, int nbytes)
该函数回来长度为nbytes字节的缓冲区buf,不管熵估量是否为0都将回来数据。运用这个函数时需求在内核空间。咱们写一个小模块来测验一下。
?
#include
#include
#include
#define NUM 10
void get_random_bytes(void *buf, int nbytes);
static int get_random_number(void)
{
unsigned long randNum[10];
int i = 0;
printk(KERN_ALERT Get some real random number.\n);
for (i=0; i
{
get_random_bytes(randNum, sizeof(unsigned long));
printk(KERN_ALERT We get random number: %ld\n, randNum);
}
return 0;
}
static void random_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如下:
?
obj-m = get_random_num.o
KDIR = $(shell uname -r)
PWD = $(shell pwd)
all:
make -C [img]file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\)A[Y)I~](ZC9Z[3Y)IDK7LK.gif[/img]b/modules/$(KDIR)file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\OOY5$4OW5H`8`9%(9$)T67M.gifild M=$(PWD) modules
clean:
make -C [img]file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\)A[Y)I~](ZC9Z[3Y)IDK7LK.gif[/img]b/modules/$(KDIR)file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\OOY5$4OW5H`8`9%(9$)T67M.gifild M=$(PWD) clean
#end#
编译之后加载模块,经过dmesg指令输出体系log最新的信息,能够看到咱们的小模块输出了10个从内核熵池中得到的随机数。卸载模块后再次加载能够从头获取新的随机数,调查输出成果,与之前得到的随机数彻底不一样。
[37972.467955] Get some real random number.
[37972.468392] We get random number: -82199505
[37972.468580] We get random number: -276237802
[37972.468586] We get random number: 411869317
[37972.468590] We get random number: 1779353222
[37972.468594] We get random number: 823507551
[37972.468598] We get random number: 1061461415
[37972.468602] We get random number: 1372137935
[37972.468606] We get random number: 1460835009
[37972.468610] We get random number: 2002191729
[37972.468614] We get random number: -272204344
[38059.349589] quit get_random_num.
[38070.575433] Get some real random number.
[38070.575462] We get random number: 1111808207
[38070.575476] We get random number: -13789055