📄 random.c
字号:
if (get_user(ent_count, (int *) arg)) return -EFAULT; /* * Add i to entropy_count, limiting the result to be * between 0 and POOLBITS. */ if (ent_count < -random_state.entropy_count) random_state.entropy_count = 0; else if (ent_count > POOLBITS) random_state.entropy_count = POOLBITS; else { random_state.entropy_count += ent_count; if (random_state.entropy_count > POOLBITS) random_state.entropy_count = POOLBITS; if (random_state.entropy_count < 0) random_state.entropy_count = 0; } /* * Wake up waiting processes if we have enough * entropy. */ if (random_state.entropy_count >= WAIT_INPUT_BITS) wake_up_interruptible(&random_read_wait); return 0; case RNDGETPOOL: if (!capable(CAP_SYS_ADMIN)) return -EPERM; p = (int *) arg; ent_count = random_state.entropy_count; if (put_user(ent_count, p++)) return -EFAULT; if (get_user(size, p)) return -EFAULT; if (put_user(POOLWORDS, p++)) return -EFAULT; if (size < 0) return -EINVAL; if (size > POOLWORDS) size = POOLWORDS; if (copy_to_user(p, random_state.pool, size*sizeof(__u32))) return -EFAULT; return 0; case RNDADDENTROPY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; p = (int *) arg; if (get_user(ent_count, p++)) return -EFAULT; if (ent_count < 0) return -EINVAL; if (get_user(size, p++)) return -EFAULT; retval = random_write(file, (const char *) p, size, &file->f_pos); if (retval < 0) return retval; /* * Add ent_count to entropy_count, limiting the result to be * between 0 and POOLBITS. */ if (ent_count > POOLBITS) random_state.entropy_count = POOLBITS; else { random_state.entropy_count += ent_count; if (random_state.entropy_count > POOLBITS) random_state.entropy_count = POOLBITS; if (random_state.entropy_count < 0) random_state.entropy_count = 0; } /* * Wake up waiting processes if we have enough * entropy. */ if (random_state.entropy_count >= WAIT_INPUT_BITS) wake_up_interruptible(&random_read_wait); return 0; case RNDZAPENTCNT: if (!capable(CAP_SYS_ADMIN)) return -EPERM; random_state.entropy_count = 0; return 0; case RNDCLEARPOOL: /* Clear the entropy pool and associated counters. */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; rand_clear_pool(); return 0; default: return -EINVAL; }}struct file_operations random_fops = { NULL, /* random_lseek */ random_read, random_write, NULL, /* random_readdir */ random_poll, /* random_poll */ random_ioctl, NULL, /* random_mmap */ NULL, /* no special open code */ NULL, /* flush */ NULL /* no special release code */};struct file_operations urandom_fops = { NULL, /* unrandom_lseek */ random_read_unlimited, random_write, NULL, /* urandom_readdir */ NULL, /* urandom_poll */ random_ioctl, NULL, /* urandom_mmap */ NULL, /* no special open code */ NULL, /* flush */ NULL /* no special release code */};/* * TCP initial sequence number picking. This uses the random number * generator to pick an initial secret value. This value is hashed * along with the TCP endpoint information to provide a unique * starting point for each pair of TCP endpoints. This defeats * attacks which rely on guessing the initial TCP sequence number. * This algorithm was suggested by Steve Bellovin. * * Using a very strong hash was taking an appreciable amount of the total * TCP connection establishment time, so this is a weaker hash, * compensated for by changing the secret periodically. *//* F, G and H are basic MD4 functions: selection, majority, parity */#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))#define H(x, y, z) ((x) ^ (y) ^ (z))/* * The generic round function. The application is so specific that * we don't bother protecting all the arguments with parens, as is generally * good macro practice, in favor of extra legibility. * Rotation is separate from addition to prevent recomputation */#define ROUND(f, a, b, c, d, x, s) \ (a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))#define K1 0#define K2 013240474631UL#define K3 015666365641UL/* * Basic cut-down MD4 transform. Returns only 32 bits of result. */static __u32 halfMD4Transform (__u32 const buf[4], __u32 const in[8]){ __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; /* Round 1 */ ROUND(F, a, b, c, d, in[0] + K1, 3); ROUND(F, d, a, b, c, in[1] + K1, 7); ROUND(F, c, d, a, b, in[2] + K1, 11); ROUND(F, b, c, d, a, in[3] + K1, 19); ROUND(F, a, b, c, d, in[4] + K1, 3); ROUND(F, d, a, b, c, in[5] + K1, 7); ROUND(F, c, d, a, b, in[6] + K1, 11); ROUND(F, b, c, d, a, in[7] + K1, 19); /* Round 2 */ ROUND(G, a, b, c, d, in[1] + K2, 3); ROUND(G, d, a, b, c, in[3] + K2, 5); ROUND(G, c, d, a, b, in[5] + K2, 9); ROUND(G, b, c, d, a, in[7] + K2, 13); ROUND(G, a, b, c, d, in[0] + K2, 3); ROUND(G, d, a, b, c, in[2] + K2, 5); ROUND(G, c, d, a, b, in[4] + K2, 9); ROUND(G, b, c, d, a, in[6] + K2, 13); /* Round 3 */ ROUND(H, a, b, c, d, in[3] + K3, 3); ROUND(H, d, a, b, c, in[7] + K3, 9); ROUND(H, c, d, a, b, in[2] + K3, 11); ROUND(H, b, c, d, a, in[6] + K3, 15); ROUND(H, a, b, c, d, in[1] + K3, 3); ROUND(H, d, a, b, c, in[5] + K3, 9); ROUND(H, c, d, a, b, in[0] + K3, 11); ROUND(H, b, c, d, a, in[4] + K3, 15); return buf[1] + b; /* "most hashed" word */ /* Alternative: return sum of all words? */}#if 0 /* May be needed for IPv6 */static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12]){ __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; /* Round 1 */ ROUND(F, a, b, c, d, in[ 0] + K1, 3); ROUND(F, d, a, b, c, in[ 1] + K1, 7); ROUND(F, c, d, a, b, in[ 2] + K1, 11); ROUND(F, b, c, d, a, in[ 3] + K1, 19); ROUND(F, a, b, c, d, in[ 4] + K1, 3); ROUND(F, d, a, b, c, in[ 5] + K1, 7); ROUND(F, c, d, a, b, in[ 6] + K1, 11); ROUND(F, b, c, d, a, in[ 7] + K1, 19); ROUND(F, a, b, c, d, in[ 8] + K1, 3); ROUND(F, d, a, b, c, in[ 9] + K1, 7); ROUND(F, c, d, a, b, in[10] + K1, 11); ROUND(F, b, c, d, a, in[11] + K1, 19); /* Round 2 */ ROUND(G, a, b, c, d, in[ 1] + K2, 3); ROUND(G, d, a, b, c, in[ 3] + K2, 5); ROUND(G, c, d, a, b, in[ 5] + K2, 9); ROUND(G, b, c, d, a, in[ 7] + K2, 13); ROUND(G, a, b, c, d, in[ 9] + K2, 3); ROUND(G, d, a, b, c, in[11] + K2, 5); ROUND(G, c, d, a, b, in[ 0] + K2, 9); ROUND(G, b, c, d, a, in[ 2] + K2, 13); ROUND(G, a, b, c, d, in[ 4] + K2, 3); ROUND(G, d, a, b, c, in[ 6] + K2, 5); ROUND(G, c, d, a, b, in[ 8] + K2, 9); ROUND(G, b, c, d, a, in[10] + K2, 13); /* Round 3 */ ROUND(H, a, b, c, d, in[ 3] + K3, 3); ROUND(H, d, a, b, c, in[ 7] + K3, 9); ROUND(H, c, d, a, b, in[11] + K3, 11); ROUND(H, b, c, d, a, in[ 2] + K3, 15); ROUND(H, a, b, c, d, in[ 6] + K3, 3); ROUND(H, d, a, b, c, in[10] + K3, 9); ROUND(H, c, d, a, b, in[ 1] + K3, 11); ROUND(H, b, c, d, a, in[ 5] + K3, 15); ROUND(H, a, b, c, d, in[ 9] + K3, 3); ROUND(H, d, a, b, c, in[ 0] + K3, 9); ROUND(H, c, d, a, b, in[ 4] + K3, 11); ROUND(H, b, c, d, a, in[ 8] + K3, 15); return buf[1] + b; /* "most hashed" word */ /* Alternative: return sum of all words? */}#endif#undef ROUND#undef F#undef G#undef H#undef K1#undef K2#undef K3/* This should not be decreased so low that ISNs wrap too fast. */#define REKEY_INTERVAL 300#define HASH_BITS 24__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, __u16 sport, __u16 dport){ static __u32 rekey_time = 0; static __u32 count = 0; static __u32 secret[12]; struct timeval tv; __u32 seq; /* * Pick a random secret every REKEY_INTERVAL seconds. */ do_gettimeofday(&tv); /* We need the usecs below... */ if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) { rekey_time = tv.tv_sec; /* First three words are overwritten below. */ get_random_bytes(&secret+3, sizeof(secret)-12); count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS; } /* * Pick a unique starting offset for each TCP connection endpoints * (saddr, daddr, sport, dport). * Note that the words are placed into the first words to be * mixed in with the halfMD4. This is because the starting * vector is also a random secret (at secret+8), and further * hashing fixed data into it isn't going to improve anything, * so we should get started with the variable data. */ secret[0]=saddr; secret[1]=daddr; secret[2]=(sport << 16) + dport; seq = (halfMD4Transform(secret+8, secret) & ((1<<HASH_BITS)-1)) + count; /* * As close as possible to RFC 793, which * suggests using a 250 kHz clock. * Further reading shows this assumes 2 Mb/s networks. * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate. * That's funny, Linux has one built in! Use it! * (Networks are faster now - should this be increased?) */ seq += tv.tv_usec + tv.tv_sec*1000000;#if 0 printk("init_seq(%lx, %lx, %d, %d) = %d\n", saddr, daddr, sport, dport, seq);#endif return seq;}#ifdef CONFIG_SYN_COOKIES/* * Secure SYN cookie computation. This is the algorithm worked out by * Dan Bernstein and Eric Schenk. * * For linux I implement the 1 minute counter by looking at the jiffies clock. * The count is passed in as a parameter, so this code doesn't much care. */#define COOKIEBITS 24 /* Upper bits store count */#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)static int syncookie_init = 0;static __u32 syncookie_secret[2][16-3+HASH_BUFFER_SIZE];__u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport, __u16 dport, __u32 sseq, __u32 count, __u32 data){ __u32 tmp[16 + HASH_BUFFER_SIZE + HASH_EXTRA_SIZE]; __u32 seq; /* * Pick two random secrets the first time we need a cookie. */ if (syncookie_init == 0) { get_random_bytes(syncookie_secret, sizeof(syncookie_secret)); syncookie_init = 1; } /* * Compute the secure sequence number. * The output should be: * HASH(sec1,saddr,sport,daddr,dport,sec1) + sseq + (count * 2^24) * + (HASH(sec2,saddr,sport,daddr,dport,count,sec2) % 2^24). * Where sseq is their sequence number and count increases every * minute by 1. * As an extra hack, we add a small "data" value that encodes the * MSS into the second hash value. */ memcpy(tmp+3, syncookie_secret[0], sizeof(syncookie_secret[0])); tmp[0]=saddr; tmp[1]=daddr; tmp[2]=(sport << 16) + dport; HASH_TRANSFORM(tmp+16, tmp); seq = tmp[17] + sseq + (count << COOKIEBITS); memcpy(tmp+3, syncookie_secret[1], sizeof(syncookie_secret[1])); tmp[0]=saddr; tmp[1]=daddr; tmp[2]=(sport << 16) + dport; tmp[3] = count; /* minute counter */ HASH_TRANSFORM(tmp+16, tmp); /* Add in the second hash and the data */ return seq + ((tmp[17] + data) & COOKIEMASK);}/* * This retrieves the small "data" value from the syncookie. * If the syncookie is bad, the data returned will be out of * range. This must be checked by the caller. * * The count value used to generate the cookie must be within * "maxdiff" if the current (passed-in) "count". The return value * is (__u32)-1 if this test fails. */__u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr, __u16 sport, __u16 dport, __u32 sseq, __u32 count, __u32 maxdiff){ __u32 tmp[16 + HASH_BUFFER_SIZE + HASH_EXTRA_SIZE]; __u32 diff; if (syncookie_init == 0) return (__u32)-1; /* Well, duh! */ /* Strip away the layers from the cookie */ memcpy(tmp+3, syncookie_secret[0], sizeof(syncookie_secret[0])); tmp[0]=saddr; tmp[1]=daddr; tmp[2]=(sport << 16) + dport; HASH_TRANSFORM(tmp+16, tmp); cookie -= tmp[17] + sseq; /* Cookie is now reduced to (count * 2^24) ^ (hash % 2^24) */ diff = (count - (cookie >> COOKIEBITS)) & ((__u32)-1 >> COOKIEBITS); if (diff >= maxdiff) return (__u32)-1; memcpy(tmp+3, syncookie_secret[1], sizeof(syncookie_secret[1])); tmp[0] = saddr; tmp[1] = daddr; tmp[2] = (sport << 16) + dport; tmp[3] = count - diff; /* minute counter */ HASH_TRANSFORM(tmp+16, tmp); return (cookie - tmp[17]) & COOKIEMASK; /* Leaving the data behind */}#endif#ifdef RANDOM_BENCHMARK/* * This is so we can do some benchmarking of the random driver, to see * how much overhead add_timer_randomness really takes. This only * works on a Pentium, since it depends on the timer clock... * * Note: the results of this benchmark as of this writing (5/27/96) * * On a Pentium, add_timer_randomness() takes between 150 and 1000 * clock cycles, with an average of around 600 clock cycles. On a 75 * MHz Pentium, this translates to 2 to 13 microseconds, with an * average time of 8 microseconds. This should be fast enough so we * can use add_timer_randomness() even with the fastest of interrupts... */static inline unsigned long long get_clock_cnt(void){ unsigned long low, high; __asm__(".byte 0x0f,0x31" :"=a" (low), "=d" (high)); return (((unsigned long long) high << 32) | low); }__initfunc(static voidinitialize_benchmark(struct random_benchmark *bench, const char *descr, int unit)){ bench->times = 0; bench->accum = 0; bench->max = 0; bench->min = 1 << 31; bench->descr = descr; bench->unit = unit;}static void begin_benchmark(struct random_benchmark *bench){#ifdef BENCHMARK_NOINT save_flags(bench->flags); cli();#endif bench->start_time = get_clock_cnt();}static void end_benchmark(struct random_benchmark *bench){ unsigned long ticks; ticks = (unsigned long) (get_clock_cnt() - bench->start_time);#ifdef BENCHMARK_NOINT restore_flags(bench->flags);#endif if (ticks < bench->min) bench->min = ticks; if (ticks > bench->max) bench->max = ticks; bench->accum += ticks; bench->times++; if (bench->times == BENCHMARK_INTERVAL) { printk("Random benchmark: %s %d: %lu min, %lu avg, " "%lu max\n", bench->descr, bench->unit, bench->min, bench->accum / BENCHMARK_INTERVAL, bench->max); bench->times = 0; bench->accum = 0; bench->max = 0; bench->min = 1 << 31; }} #endif /* RANDOM_BENCHMARK */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -