random.c

来自「linux 内核源代码」· C语言 代码 · 共 1,669 行 · 第 1/4 页

C
1,669
字号
	.lock = __SPIN_LOCK_UNLOCKED(&input_pool.lock),	.pool = input_pool_data};static struct entropy_store blocking_pool = {	.poolinfo = &poolinfo_table[1],	.name = "blocking",	.limit = 1,	.pull = &input_pool,	.lock = __SPIN_LOCK_UNLOCKED(&blocking_pool.lock),	.pool = blocking_pool_data};static struct entropy_store nonblocking_pool = {	.poolinfo = &poolinfo_table[1],	.name = "nonblocking",	.pull = &input_pool,	.lock = __SPIN_LOCK_UNLOCKED(&nonblocking_pool.lock),	.pool = nonblocking_pool_data};/* * This function adds a byte into the entropy "pool".  It does not * update the entropy estimate.  The caller should call * credit_entropy_store if this is appropriate. * * The pool is stirred with a primitive polynomial of the appropriate * degree, and then twisted.  We twist by three bits at a time because * it's cheap to do so and helps slightly in the expected case where * the entropy is concentrated in the low-order bits. */static void __add_entropy_words(struct entropy_store *r, const __u32 *in,				int nwords, __u32 out[16]){	static __u32 const twist_table[8] = {		0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,		0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };	unsigned long i, add_ptr, tap1, tap2, tap3, tap4, tap5;	int new_rotate, input_rotate;	int wordmask = r->poolinfo->poolwords - 1;	__u32 w, next_w;	unsigned long flags;	/* Taps are constant, so we can load them without holding r->lock.  */	tap1 = r->poolinfo->tap1;	tap2 = r->poolinfo->tap2;	tap3 = r->poolinfo->tap3;	tap4 = r->poolinfo->tap4;	tap5 = r->poolinfo->tap5;	next_w = *in++;	spin_lock_irqsave(&r->lock, flags);	prefetch_range(r->pool, wordmask);	input_rotate = r->input_rotate;	add_ptr = r->add_ptr;	while (nwords--) {		w = rol32(next_w, input_rotate);		if (nwords > 0)			next_w = *in++;		i = add_ptr = (add_ptr - 1) & wordmask;		/*		 * Normally, we add 7 bits of rotation to the pool.		 * At the beginning of the pool, add an extra 7 bits		 * rotation, so that successive passes spread the		 * input bits across the pool evenly.		 */		new_rotate = input_rotate + 14;		if (i)			new_rotate = input_rotate + 7;		input_rotate = new_rotate & 31;		/* XOR in the various taps */		w ^= r->pool[(i + tap1) & wordmask];		w ^= r->pool[(i + tap2) & wordmask];		w ^= r->pool[(i + tap3) & wordmask];		w ^= r->pool[(i + tap4) & wordmask];		w ^= r->pool[(i + tap5) & wordmask];		w ^= r->pool[i];		r->pool[i] = (w >> 3) ^ twist_table[w & 7];	}	r->input_rotate = input_rotate;	r->add_ptr = add_ptr;	if (out) {		for (i = 0; i < 16; i++) {			out[i] = r->pool[add_ptr];			add_ptr = (add_ptr - 1) & wordmask;		}	}	spin_unlock_irqrestore(&r->lock, flags);}static inline void add_entropy_words(struct entropy_store *r, const __u32 *in,				     int nwords){	__add_entropy_words(r, in, nwords, NULL);}/* * Credit (or debit) the entropy store with n bits of entropy */static void credit_entropy_store(struct entropy_store *r, int nbits){	unsigned long flags;	spin_lock_irqsave(&r->lock, flags);	if (r->entropy_count + nbits < 0) {		DEBUG_ENT("negative entropy/overflow (%d+%d)\n",			  r->entropy_count, nbits);		r->entropy_count = 0;	} else if (r->entropy_count + nbits > r->poolinfo->POOLBITS) {		r->entropy_count = r->poolinfo->POOLBITS;	} else {		r->entropy_count += nbits;		if (nbits)			DEBUG_ENT("added %d entropy credits to %s\n",				  nbits, r->name);	}	spin_unlock_irqrestore(&r->lock, flags);}/********************************************************************* * * Entropy input management * *********************************************************************//* There is one of these per entropy source */struct timer_rand_state {	cycles_t last_time;	long last_delta,last_delta2;	unsigned dont_count_entropy:1;};static struct timer_rand_state input_timer_state;static struct timer_rand_state *irq_timer_state[NR_IRQS];/* * This function adds entropy to the entropy "pool" by using timing * delays.  It uses the timer_rand_state structure to make an estimate * of how many bits of entropy this call has added to the pool. * * The number "num" is also added to the pool - it should somehow describe * the type of event which just happened.  This is currently 0-255 for * keyboard scan codes, and 256 upwards for interrupts. * */static void add_timer_randomness(struct timer_rand_state *state, unsigned num){	struct {		cycles_t cycles;		long jiffies;		unsigned num;	} sample;	long delta, delta2, delta3;	preempt_disable();	/* if over the trickle threshold, use only 1 in 4096 samples */	if (input_pool.entropy_count > trickle_thresh &&	    (__get_cpu_var(trickle_count)++ & 0xfff))		goto out;	sample.jiffies = jiffies;	sample.cycles = get_cycles();	sample.num = num;	add_entropy_words(&input_pool, (u32 *)&sample, sizeof(sample)/4);	/*	 * Calculate number of bits of randomness we probably added.	 * We take into account the first, second and third-order deltas	 * in order to make our estimate.	 */	if (!state->dont_count_entropy) {		delta = sample.jiffies - state->last_time;		state->last_time = sample.jiffies;		delta2 = delta - state->last_delta;		state->last_delta = delta;		delta3 = delta2 - state->last_delta2;		state->last_delta2 = delta2;		if (delta < 0)			delta = -delta;		if (delta2 < 0)			delta2 = -delta2;		if (delta3 < 0)			delta3 = -delta3;		if (delta > delta2)			delta = delta2;		if (delta > delta3)			delta = delta3;		/*		 * delta is now minimum absolute delta.		 * Round down by 1 bit on general principles,		 * and limit entropy entimate to 12 bits.		 */		credit_entropy_store(&input_pool,				     min_t(int, fls(delta>>1), 11));	}	if(input_pool.entropy_count >= random_read_wakeup_thresh)		wake_up_interruptible(&random_read_wait);out:	preempt_enable();}void add_input_randomness(unsigned int type, unsigned int code,				 unsigned int value){	static unsigned char last_value;	/* ignore autorepeat and the like */	if (value == last_value)		return;	DEBUG_ENT("input event\n");	last_value = value;	add_timer_randomness(&input_timer_state,			     (type << 4) ^ code ^ (code >> 4) ^ value);}EXPORT_SYMBOL_GPL(add_input_randomness);void add_interrupt_randomness(int irq){	if (irq >= NR_IRQS || irq_timer_state[irq] == NULL)		return;	DEBUG_ENT("irq event %d\n", irq);	add_timer_randomness(irq_timer_state[irq], 0x100 + irq);}#ifdef CONFIG_BLOCKvoid add_disk_randomness(struct gendisk *disk){	if (!disk || !disk->random)		return;	/* first major is 1, so we get >= 0x200 here */	DEBUG_ENT("disk event %d:%d\n", disk->major, disk->first_minor);	add_timer_randomness(disk->random,			     0x100 + MKDEV(disk->major, disk->first_minor));}EXPORT_SYMBOL(add_disk_randomness);#endif#define EXTRACT_SIZE 10/********************************************************************* * * Entropy extraction routines * *********************************************************************/static ssize_t extract_entropy(struct entropy_store *r, void * buf,			       size_t nbytes, int min, int rsvd);/* * 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 void xfer_secondary_pool(struct entropy_store *r, size_t nbytes){	__u32 tmp[OUTPUT_POOL_WORDS];	if (r->pull && r->entropy_count < nbytes * 8 &&	    r->entropy_count < r->poolinfo->POOLBITS) {		/* If we're limited, always leave two wakeup worth's BITS */		int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4;		int bytes = nbytes;		/* pull at least as many as BYTES as wakeup BITS */		bytes = max_t(int, bytes, random_read_wakeup_thresh / 8);		/* but never more than the buffer size */		bytes = min_t(int, bytes, sizeof(tmp));		DEBUG_ENT("going to reseed %s with %d bits "			  "(%d of %d requested)\n",			  r->name, bytes * 8, nbytes * 8, r->entropy_count);		bytes=extract_entropy(r->pull, tmp, bytes,				      random_read_wakeup_thresh / 8, rsvd);		add_entropy_words(r, tmp, (bytes + 3) / 4);		credit_entropy_store(r, bytes*8);	}}/* * These functions extracts randomness from the "entropy pool", and * returns it in a buffer. * * The min parameter specifies the minimum amount we can pull before * failing to avoid races that defeat catastrophic reseeding while the * reserved parameter indicates how much entropy we must leave in the * pool after each pull to avoid starving other readers. * * Note: extract_entropy() assumes that .poolwords is a multiple of 16 words. */static size_t account(struct entropy_store *r, size_t nbytes, int min,		      int reserved){	unsigned long flags;	BUG_ON(r->entropy_count > r->poolinfo->POOLBITS);	/* Hold lock while accounting */	spin_lock_irqsave(&r->lock, flags);	DEBUG_ENT("trying to extract %d bits from %s\n",		  nbytes * 8, r->name);	/* Can we pull enough? */	if (r->entropy_count / 8 < min + reserved) {		nbytes = 0;	} else {		/* If limited, never pull more than available */		if (r->limit && nbytes + reserved >= r->entropy_count / 8)			nbytes = r->entropy_count/8 - reserved;		if(r->entropy_count / 8 >= nbytes + reserved)			r->entropy_count -= nbytes*8;		else			r->entropy_count = reserved;		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, r->limit ? "" : " (unlimited)");	spin_unlock_irqrestore(&r->lock, flags);	return nbytes;}static void extract_buf(struct entropy_store *r, __u8 *out){	int i;	__u32 data[16], buf[5 + SHA_WORKSPACE_WORDS];	sha_init(buf);	/*	 * 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; i < r->poolinfo->poolwords; i += 16) {		/* hash blocks of 16 words = 512 bits */		sha_transform(buf, (__u8 *)(r->pool + i), buf + 5);		/* feed back portion of the resulting hash */		add_entropy_words(r, &buf[i % 5], 1);	}	/*	 * To avoid duplicates, we atomically extract a	 * portion of the pool while mixing, and hash one	 * final time.	 */	__add_entropy_words(r, &buf[i % 5], 1, data);	sha_transform(buf, (__u8 *)data, buf + 5);	/*	 * In case the hash function has some recognizable	 * output pattern, we fold it in half.	 */	buf[0] ^= buf[3];	buf[1] ^= buf[4];	buf[2] ^= rol32(buf[2], 16);	memcpy(out, buf, EXTRACT_SIZE);	memset(buf, 0, sizeof(buf));}static ssize_t extract_entropy(struct entropy_store *r, void * buf,			       size_t nbytes, int min, int reserved){	ssize_t ret = 0, i;	__u8 tmp[EXTRACT_SIZE];	xfer_secondary_pool(r, nbytes);	nbytes = account(r, nbytes, min, reserved);	while (nbytes) {		extract_buf(r, tmp);		i = min_t(int, nbytes, EXTRACT_SIZE);		memcpy(buf, tmp, i);		nbytes -= i;		buf += i;		ret += i;	}	/* Wipe data just returned from memory */	memset(tmp, 0, sizeof(tmp));	return ret;}static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,				    size_t nbytes){	ssize_t ret = 0, i;	__u8 tmp[EXTRACT_SIZE];

⌨️ 快捷键说明

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