2 * THE BEER-WARE LICENSE
4 * <dan@FreeBSD.ORG> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you
6 * think this stuff is worth it, you can buy me a beer in return.
10 * $FreeBSD: src/sys/libkern/arc4random.c,v 1.3.2.2 2001/09/17 07:06:50 silby Exp $
11 * $DragonFly: src/sys/libkern/arc4random.c,v 1.3 2006/09/03 17:31:55 dillon Exp $
14 #include <sys/types.h>
15 #include <sys/systm.h>
16 #include <sys/random.h>
17 #include <sys/libkern.h>
20 #include <vm/vm_extern.h>
22 #define ARC4_MAXRUNS 16384
23 #define ARC4_RESEED_SECONDS 300
24 #define ARC4_KEYBYTES 32 /* 256 bit key */
30 time_t arc4_nextreseed;
31 uint8_t arc4_sbox[256];
34 static struct arc4_data *arc4_data_pcpu[MAXCPU];
36 static uint8_t arc4_randbyte(struct arc4_data *);
39 arc4_swap(uint8_t *a, uint8_t *b)
52 arc4_randomstir(struct arc4_data *d)
58 * XXX read_random() returns unsafe numbers if the entropy
59 * device is not loaded -- MarkM.
61 r = read_random_unlimited(key, ARC4_KEYBYTES);
62 /* If r == 0 || -1, just use what was on the stack. */
64 for (n = r; n < sizeof(key); n++)
68 for (n = 0; n < 256; n++) {
69 d->arc4_j = (d->arc4_j + d->arc4_sbox[n] + key[n]) % 256;
70 arc4_swap(&d->arc4_sbox[n], &d->arc4_sbox[d->arc4_j]);
74 * Discard early keystream, as per recommendations in:
75 * "(Not So) Random Shuffles of RC4" by Ilya Mironov.
77 for (n = 0; n < 768 * 4; n++)
80 /* Reset for next reseed cycle. */
81 d->arc4_nextreseed = time_uptime + ARC4_RESEED_SECONDS;
86 * Generate a random byte.
89 arc4_randbyte(struct arc4_data *d)
93 d->arc4_i = (d->arc4_i + 1) % 256;
94 d->arc4_j = (d->arc4_j + d->arc4_sbox[d->arc4_i]) % 256;
96 arc4_swap(&d->arc4_sbox[d->arc4_i], &d->arc4_sbox[d->arc4_j]);
98 arc4_t = (d->arc4_sbox[d->arc4_i] + d->arc4_sbox[d->arc4_j]) % 256;
99 return d->arc4_sbox[arc4_t];
105 struct arc4_data *d = arc4_data_pcpu[mycpuid];
108 if (++(d->arc4_numruns) > ARC4_MAXRUNS ||
109 time_uptime > d->arc4_nextreseed)
112 ret = arc4_randbyte(d);
113 ret |= arc4_randbyte(d) << 8;
114 ret |= arc4_randbyte(d) << 16;
115 ret |= arc4_randbyte(d) << 24;
123 struct arc4_data *d = arc4_data_pcpu[mycpuid];
126 if (++(d->arc4_numruns) > ARC4_MAXRUNS ||
127 time_uptime > d->arc4_nextreseed)
130 ret = arc4_randbyte(d);
131 ret |= arc4_randbyte(d) << 8;
132 ret |= arc4_randbyte(d) << 16;
133 ret |= arc4_randbyte(d) << 24;
134 ret |= (uint64_t)arc4_randbyte(d) << 32;
135 ret |= (uint64_t)arc4_randbyte(d) << 40;
136 ret |= (uint64_t)arc4_randbyte(d) << 48;
137 ret |= (uint64_t)arc4_randbyte(d) << 56;
143 karc4rand(void *ptr, size_t len)
145 struct arc4_data *d = arc4_data_pcpu[mycpuid];
149 /* No one call this function in ISR/ithread. */
153 if (++(d->arc4_numruns) > ARC4_MAXRUNS ||
154 time_uptime > d->arc4_nextreseed)
158 *p++ = arc4_randbyte(d);
166 * Initialize our S-box to its beginning defaults.
169 arc4_init_pcpu(int cpuid)
174 KASSERT(arc4_data_pcpu[cpuid] == NULL,
175 ("arc4 was initialized on cpu%d", cpuid));
177 d = (void *)kmem_alloc3(&kernel_map, sizeof(*d), VM_SUBSYS_GD,
179 memset(d, 0, sizeof(*d));
181 for (n = 0; n < 256; n++)
182 d->arc4_sbox[n] = (uint8_t)n;
187 * Discard early keystream, as per recommendations in:
188 * "(Not So) Random Shuffles of RC4" by Ilya Mironov.
190 for (n = 0; n < 768 * 4; n++)
193 arc4_data_pcpu[cpuid] = d;