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 + -
显示快捷键?