random.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,115 行 · 第 1/5 页

C
2,115
字号
	MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);	MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);	MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6);	MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);	MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);	MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);	MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6);	MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);	MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);	MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);	buf[0] += a;	buf[1] += b;	buf[2] += c;	buf[3] += d;}#undef F1#undef F2#undef F3#undef F4#undef MD5STEP#endif /* !USE_SHA *//********************************************************************* * * Entropy extraction routines * *********************************************************************/#define EXTRACT_ENTROPY_USER		1#define EXTRACT_ENTROPY_SECONDARY	2#define EXTRACT_ENTROPY_LIMIT		4#define TMP_BUF_SIZE			(HASH_BUFFER_SIZE + HASH_EXTRA_SIZE)#define SEC_XFER_SIZE			(TMP_BUF_SIZE*4)static ssize_t extract_entropy(struct entropy_store *r, void * buf,			       size_t nbytes, int flags);/* * This utility inline function is responsible for transfering entropy * from the primary pool to the secondary extraction pool. We make * sure we pull enough for a 'catastrophic reseed'. */static inline void xfer_secondary_pool(struct entropy_store *r,				       size_t nbytes, __u32 *tmp){	if (r->entropy_count < nbytes * 8 &&	    r->entropy_count < r->poolinfo.POOLBITS) {		int bytes = max_t(int, random_read_wakeup_thresh / 8,				min_t(int, nbytes, TMP_BUF_SIZE));		DEBUG_ENT("%04d %04d : going to reseed %s with %d bits "			  "(%d of %d requested)\n",			  random_state->entropy_count,			  sec_random_state->entropy_count,			  r->name, bytes * 8, nbytes * 8, r->entropy_count);		bytes=extract_entropy(random_state, tmp, bytes,				      EXTRACT_ENTROPY_LIMIT);		add_entropy_words(r, tmp, bytes);		credit_entropy_store(r, bytes*8);	}}/* * This function extracts randomness from the "entropy pool", and * returns it in a buffer.  This function computes how many remaining * bits of entropy are left in the pool, but it does not restrict the * number of bytes that are actually obtained.  If the EXTRACT_ENTROPY_USER * flag is given, then the buf pointer is assumed to be in user space. * * If the EXTRACT_ENTROPY_SECONDARY flag is given, then we are actually * extracting entropy from the secondary pool, and can refill from the * primary pool if needed. * * Note: extract_entropy() assumes that .poolwords is a multiple of 16 words. */static ssize_t extract_entropy(struct entropy_store *r, void * buf,			       size_t nbytes, int flags){	ssize_t ret, i;	__u32 tmp[TMP_BUF_SIZE];	__u32 x;	unsigned long cpuflags;	/* Redundant, but just in case... */	if (r->entropy_count > r->poolinfo.POOLBITS)		r->entropy_count = r->poolinfo.POOLBITS;	if (flags & EXTRACT_ENTROPY_SECONDARY)		xfer_secondary_pool(r, nbytes, tmp);	/* Hold lock while accounting */	spin_lock_irqsave(&r->lock, cpuflags);	DEBUG_ENT("%04d %04d : trying to extract %d bits from %s\n",		  random_state->entropy_count,		  sec_random_state->entropy_count,		  nbytes * 8, r->name);	if (flags & EXTRACT_ENTROPY_LIMIT && nbytes >= r->entropy_count / 8)		nbytes = r->entropy_count / 8;	if (r->entropy_count / 8 >= nbytes)		r->entropy_count -= nbytes*8;	else		r->entropy_count = 0;	if (r->entropy_count < random_write_wakeup_thresh)		wake_up_interruptible(&random_write_wait);	DEBUG_ENT("Debiting %d entropy credits from %s%s\n",		  nbytes * 8, r->name,		  flags & EXTRACT_ENTROPY_LIMIT ? "" : " (unlimited)");	spin_unlock_irqrestore(&r->lock, cpuflags);	ret = 0;	while (nbytes) {		/*		 * Check if we need to break out or reschedule....		 */		if ((flags & EXTRACT_ENTROPY_USER) && need_resched()) {			if (signal_pending(current)) {				if (ret == 0)					ret = -ERESTARTSYS;				break;			}			DEBUG_ENT("%04d %04d : extract feeling sleepy (%d bytes left)\n",				  random_state->entropy_count,				  sec_random_state->entropy_count, nbytes);			schedule();			DEBUG_ENT("%04d %04d : extract woke up\n",				  random_state->entropy_count,				  sec_random_state->entropy_count);		}		/* Hash the pool to get the output */		tmp[0] = 0x67452301;		tmp[1] = 0xefcdab89;		tmp[2] = 0x98badcfe;		tmp[3] = 0x10325476;#ifdef USE_SHA		tmp[4] = 0xc3d2e1f0;#endif		/*		 * As we hash the pool, we mix intermediate values of		 * the hash back into the pool.  This eliminates		 * backtracking attacks (where the attacker knows		 * the state of the pool plus the current outputs, and		 * attempts to find previous ouputs), unless the hash		 * function can be inverted.		 */		for (i = 0, x = 0; i < r->poolinfo.poolwords; i += 16, x+=2) {			HASH_TRANSFORM(tmp, r->pool+i);			add_entropy_words(r, &tmp[x%HASH_BUFFER_SIZE], 1);		}				/*		 * In case the hash function has some recognizable		 * output pattern, we fold it in half.		 */		for (i = 0; i <  HASH_BUFFER_SIZE/2; i++)			tmp[i] ^= tmp[i + (HASH_BUFFER_SIZE+1)/2];#if HASH_BUFFER_SIZE & 1	/* There's a middle word to deal with */		x = tmp[HASH_BUFFER_SIZE/2];		x ^= (x >> 16);		/* Fold it in half */		((__u16 *)tmp)[HASH_BUFFER_SIZE-1] = (__u16)x;#endif				/* Copy data to destination buffer */		i = min(nbytes, HASH_BUFFER_SIZE*sizeof(__u32)/2);		if (flags & EXTRACT_ENTROPY_USER) {			i -= copy_to_user(buf, (__u8 const *)tmp, i);			if (!i) {				ret = -EFAULT;				break;			}		} else			memcpy(buf, (__u8 const *)tmp, i);		nbytes -= i;		buf += i;		ret += i;	}	/* Wipe data just returned from memory */	memset(tmp, 0, sizeof(tmp));		return ret;}/* * This function is the exported kernel interface.  It returns some * number of good random numbers, suitable for seeding TCP sequence * numbers, etc. */void get_random_bytes(void *buf, int nbytes){	struct entropy_store *r = urandom_state;	int flags = EXTRACT_ENTROPY_SECONDARY;	if (!r)		r = sec_random_state;	if (!r) {		r = random_state;		flags = 0;	}	if (!r) {		printk(KERN_NOTICE "get_random_bytes called before "				   "random driver initialization\n");		return;	}	extract_entropy(r, (char *) buf, nbytes, flags);}EXPORT_SYMBOL(get_random_bytes);/********************************************************************* * * Functions to interface with Linux * *********************************************************************//* * Initialize the random pool with standard stuff. * * NOTE: This is an OS-dependent function. */static void init_std_data(struct entropy_store *r){	struct timeval 	tv;	__u32		words[2];	char 		*p;	int		i;	do_gettimeofday(&tv);	words[0] = tv.tv_sec;	words[1] = tv.tv_usec;	add_entropy_words(r, words, 2);	/*	 *	This doesn't lock system.utsname. However, we are generating	 *	entropy so a race with a name set here is fine.	 */	p = (char *) &system_utsname;	for (i = sizeof(system_utsname) / sizeof(words); i; i--) {		memcpy(words, p, sizeof(words));		add_entropy_words(r, words, sizeof(words)/4);		p += sizeof(words);	}}static int __init rand_initialize(void){	int i;	if (create_entropy_store(DEFAULT_POOL_SIZE, "primary", &random_state))		goto err;	if (batch_entropy_init(BATCH_ENTROPY_SIZE, random_state))		goto err;	if (create_entropy_store(SECONDARY_POOL_SIZE, "secondary",				 &sec_random_state))		goto err;	if (create_entropy_store(SECONDARY_POOL_SIZE, "urandom",				 &urandom_state))		goto err;	clear_entropy_store(random_state);	clear_entropy_store(sec_random_state);	clear_entropy_store(urandom_state);	init_std_data(random_state);	init_std_data(sec_random_state);	init_std_data(urandom_state);#ifdef CONFIG_SYSCTL	sysctl_init_random(random_state);#endif	for (i = 0; i < NR_IRQS; i++)		irq_timer_state[i] = NULL;	memset(&keyboard_timer_state, 0, sizeof(struct timer_rand_state));	memset(&mouse_timer_state, 0, sizeof(struct timer_rand_state));	memset(&extract_timer_state, 0, sizeof(struct timer_rand_state));	extract_timer_state.dont_count_entropy = 1;	return 0;err:	return -1;}module_init(rand_initialize);void rand_initialize_irq(int irq){	struct timer_rand_state *state;		if (irq >= NR_IRQS || irq_timer_state[irq])		return;	/*	 * If kmalloc returns null, we just won't use that entropy	 * source.	 */	state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL);	if (state) {		memset(state, 0, sizeof(struct timer_rand_state));		irq_timer_state[irq] = state;	}} void rand_initialize_disk(struct gendisk *disk){	struct timer_rand_state *state;		/*	 * If kmalloc returns null, we just won't use that entropy	 * source.	 */	state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL);	if (state) {		memset(state, 0, sizeof(struct timer_rand_state));		disk->random = state;	}}static ssize_trandom_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos){	DECLARE_WAITQUEUE(wait, current);	ssize_t			n, retval = 0, count = 0;		if (nbytes == 0)		return 0;	while (nbytes > 0) {		n = nbytes;		if (n > SEC_XFER_SIZE)			n = SEC_XFER_SIZE;		DEBUG_ENT("%04d %04d : reading %d bits, p: %d s: %d\n",			  random_state->entropy_count,			  sec_random_state->entropy_count,			  n*8, random_state->entropy_count,			  sec_random_state->entropy_count);		n = extract_entropy(sec_random_state, buf, n,				    EXTRACT_ENTROPY_USER |				    EXTRACT_ENTROPY_LIMIT |				    EXTRACT_ENTROPY_SECONDARY);		DEBUG_ENT("%04d %04d : read got %d bits (%d still needed)\n",			  random_state->entropy_count,			  sec_random_state->entropy_count,			  n*8, (nbytes-n)*8);		if (n == 0) {			if (file->f_flags & O_NONBLOCK) {				retval = -EAGAIN;				break;			}			if (signal_pending(current)) {				retval = -ERESTARTSYS;				break;			}			DEBUG_ENT("%04d %04d : sleeping?\n",				  random_state->entropy_count,				  sec_random_state->entropy_count);			set_current_state(TASK_INTERRUPTIBLE);			add_wait_queue(&random_read_wait, &wait);			if (sec_random_state->entropy_count / 8 == 0)				schedule();			set_current_state(TASK_RUNNING);			remove_wait_queue(&random_read_wait, &wait);			DEBUG_ENT("%04d %04d : waking up\n",				  random_state->entropy_count,				  sec_random_state->entropy_count);			continue;		}		if (n < 0) {			retval = n;			break;		}		count += n;		buf += n;		nbytes -= n;		break;		/* This break makes the device work */				/* like a named pipe */	}	/*	 * If we gave the user some bytes, update the access time.	 */	if (count)		file_accessed(file);		return (count ? count : retval);}static ssize_turandom_read(struct file * file, char __user * buf,		      size_t nbytes, loff_t *ppos){	int flags = EXTRACT_ENTROPY_USER;	unsigned long cpuflags;	spin_lock_irqsave(&random_state->lock, cpuflags);	if (random_state->entropy_count > random_state->poolinfo.POOLBITS)		flags |= EXTRACT_ENTROPY_SECONDARY;	spin_unlock_irqrestore(&random_state->lock, cpuflags);	return extract_entropy(urandom_state, buf, nbytes, flags);}static unsigned intrandom_poll(struct file *file, poll_table * wait)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?