The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
rand.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Functions to get randomness
18 *
19 * @file src/lib/util/rand.c
20 *
21 * @copyright 1999-2017 The FreeRADIUS server project
22 */
23RCSID("$Id: 5f4f7727979a4f5bcc9fb9c498143b3bb1b21eb3 $")
24
25#include <freeradius-devel/util/rand.h>
26#include <freeradius-devel/util/hash.h>
27
28#include <fcntl.h>
29
30static _Thread_local fr_randctx fr_rand_pool; //!< A pool of pre-generated random integers
32
33void fr_rand_init(void)
34{
35 int fd;
37 uint8_t *end = p + sizeof(fr_rand_pool.randrsl);
38
39 if (fr_rand_initialized) return;
40
41
42 memset(&fr_rand_pool, 0, sizeof(fr_rand_pool));
43
44 fd = open("/dev/urandom", O_RDONLY);
45 if (fd >= 0) {
46 ssize_t rcode;
47
48 while (p < end) {
49 rcode = read(fd, p, (size_t) (end - p));
50 if ((rcode < 0) && (errno != EINTR)) break;
51 if (rcode > 0) p += rcode;
52 }
53 close(fd);
54 } else {
55 /*
56 * We use unix_time, because fr_time() is
57 * nanoseconds since the server started.
58 * Which is likely a very small number.
59 * Whereas unix time is somewhat more
60 * unknown. If we're not seeding off of
61 * /dev/urandom, then any randomness we
62 * get here is terrible.
63 */
65
66 memcpy((void *) &fr_rand_pool.randrsl[0], &when, sizeof(when));
67 }
68
72}
73
74/** Seed the random number generator with a fixed value
75 *
76 * The same seed always produces the same sequence from fr_rand(), so tests
77 * can match output that includes random values. The server must never call
78 * this, as anyone who knows the seed can predict every random value.
79 *
80 * @param[in] seed to start the sequence from.
81 */
82void fr_rand_seed(uint64_t seed)
83{
84 memset(&fr_rand_pool, 0, sizeof(fr_rand_pool));
85
86 /*
87 * Set the seed one 32-bit word at a time, so the sequence
88 * is the same whatever the byte order of the host.
89 */
90 fr_rand_pool.randrsl[0] = (uint32_t)seed;
91 fr_rand_pool.randrsl[1] = (uint32_t)(seed >> 32);
92
96}
97
98/** Mix data into the random number generator.
99 *
100 * May be called any number of times.
101 */
102void fr_rand_mixin(void const *data, size_t size)
103{
105
106 /*
107 * Ensure that the pool is initialized.
108 */
109 if (!fr_rand_initialized) {
110 fr_rand_init();
111 }
112
113 /*
114 * Hash the user data
115 */
116 hash = fr_rand();
117 if (!hash) hash = fr_rand();
118 hash = fr_hash_update(data, size, hash);
119
121}
122
123
124/** Return a 32-bit random number
125 *
126 * @hidecallergraph
127 */
129{
130 uint32_t num;
131
132 /*
133 * Ensure that the pool is initialized.
134 */
135 if (!fr_rand_initialized) {
136 fr_rand_init();
137 }
138
140 if (fr_rand_pool.randcnt >= 256) {
143 }
144
145 return num;
146}
147
148void fr_rand_buffer(void *start, size_t length)
149{
150 uint32_t x;
151 uint8_t *buffer = start;
152 size_t buflen = length;
153
154 if (buflen > 4) {
155 size_t i;
156
157 for (i = 0; i <= (buflen - 4); i += 4) {
158 x = fr_rand();
159 memcpy(buffer + i, &x, sizeof(x));
160 }
161
162 /*
163 * Keep only the last bytes in the word.
164 */
165 i = buflen & ~0x03;
166 buffer += i;
167 buflen &= 0x03;
168 }
169
170 if (!buflen) return;
171
172 x = fr_rand();
173
174 memcpy(buffer, &x, buflen);
175}
176
177/** Generate a random string
178 *
179 * @note Character selection is not perfectly distributed, should not be used
180 * for cryptographic purposes.
181 *
182 * @param[out] out Where to write the string
183 * @param[in] len Length of the output buffer.
184 * @param[in] class to pick characters from (see function body).
185 */
186void fr_rand_str(uint8_t *out, size_t len, char class)
187{
188 uint8_t *p = out, *end = p + len;
189 uint32_t word;
190 unsigned int mod;
191 uint8_t byte;
192
193 /*
194 * Lookup tables for randstr char classes
195 */
196 static char randstr_punc[] = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
197 static char randstr_salt[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz/.";
198
199 /*
200 * Characters humans rarely confuse. Reduces char set considerably
201 * should only be used for things such as one time passwords.
202 */
203 static char randstr_otp[] = "469ACGHJKLMNPQRUVWXYabdfhijkprstuvwxyz";
204
205/*
206 * yeah yeah not perfect distribution
207 * but close enough.
208 */
209#define fill(_expr) do { \
210while (p < end) { \
211 if ((mod = ((p - out) & (sizeof(word) - 1))) == 0) word = fr_rand(); \
212 byte = ((uint8_t *)&word)[mod]; \
213 *p++ = (_expr); \
214} } while (0)
215
216 switch (class) {
217 /*
218 * Lowercase letters
219 */
220 case 'c':
221 fill('a' + (byte % 26));
222 return;
223
224 /*
225 * Uppercase letters
226 */
227 case 'C':
228 fill('A' + (byte % 26));
229 return;
230
231 /*
232 * Numbers
233 */
234 case 'n':
235 fill('0' + (byte % 10));
236 return;
237
238 /*
239 * Alpha numeric
240 */
241 case 'a':
242 fill(randstr_salt[byte % (sizeof(randstr_salt) - 3)]);
243 return;
244
245 /*
246 * Punctuation
247 */
248 case '!':
249 fill(randstr_punc[byte % (sizeof(randstr_punc) - 1)]);
250 return;
251
252 /*
253 * Alpha numeric + punctuation
254 */
255 case '.':
256 fill('!' + (byte % 95));
257 break;
258
259 /*
260 * Alpha numeric + salt chars './'
261 */
262 case 's':
263 fill(randstr_salt[byte % (sizeof(randstr_salt) - 1)]);
264 break;
265
266 /*
267 * Chars suitable for One Time Password tokens.
268 * Alpha numeric with easily confused char pairs removed.
269 */
270 case 'o':
271 fill(randstr_otp[byte % (sizeof(randstr_otp) - 1)]);
272 break;
273
274 /*
275 * Binary data
276 */
277 case 'b':
278 default:
279 fill(byte);
280 return;
281 }
282}
283
284
285/*
286 * http://www.cse.yorku.ca/~oz/marsaglia-rng.html
287 *
288 * We implement MWC here, which uses 2 32-bit numbers for a
289 * state, and has a period of 2^60.
290 *
291 * We could extend this to a larger RNG with 4 32-bit state
292 * numbers {a, b, c, d} and use KISS, which has a period of about
293 * 2^123.
294 *
295 * a' = 36969 * (a & 65535) + (a >> 16)
296 * b' = 18000 * (b & 65535) + (b >> 16))
297 *
298 * MWC (a' << 16) + b'
299 * SHR3 (c ^= (c <<17); c ^= ( c>>13); c ^= (c << 5))
300 * CONG d' = 69069 * d + 1234567
301 * KISS ((MWC^CONG)+SHR3)
302 */
304{
305 ctx->a = (36969 * (ctx->a & 0xffff)) + (ctx->a >> 16);
306 ctx->b = (18000 * (ctx->b & 0xffff)) + (ctx->b >> 16);
307
308 return (ctx->a << 16) + ctx->b;
309}
static int const char char buffer[256]
Definition acutest.h:641
#define _Thread_local
Definition atexit.h:213
#define RCSID(id)
Definition build.h:603
uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
Definition hash.c:900
void fr_isaac_init(fr_randctx *ctx)
Definition isaac.c:85
void fr_isaac(fr_randctx *ctx)
Definition isaac.c:46
#define fr_time()
Definition event.c:58
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
#define fill(_expr)
void fr_rand_seed(uint64_t seed)
Seed the random number generator with a fixed value.
Definition rand.c:82
static _Thread_local fr_randctx fr_rand_pool
A pool of pre-generated random integers.
Definition rand.c:30
uint32_t fr_fast_rand(fr_fast_rand_t *ctx)
Definition rand.c:303
void fr_rand_init(void)
Definition rand.c:33
static _Thread_local bool fr_rand_initialized
Definition rand.c:31
void fr_rand_str(uint8_t *out, size_t len, char class)
Generate a random string.
Definition rand.c:186
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:128
void fr_rand_buffer(void *start, size_t length)
Definition rand.c:148
void fr_rand_mixin(void const *data, size_t size)
Mix data into the random number generator.
Definition rand.c:102
uint32_t b
Definition rand.h:55
uint32_t randmem[256]
Definition rand.h:41
uint32_t randrsl[256]
Definition rand.h:40
uint32_t randcnt
Definition rand.h:39
uint32_t a
Definition rand.h:55
Smaller fast random number generator.
Definition rand.h:54
static unsigned int hash(char const *username, unsigned int tablesize)
Definition rlm_passwd.c:132
static uint64_t fr_unix_time_unwrap(fr_unix_time_t time)
Definition time.h:161
static fr_unix_time_t fr_time_to_unix_time(fr_time_t when)
Convert an fr_time_t (internal time) to our version of unix time (wallclock time)
Definition time.h:688
static fr_slen_t data
Definition value.h:1366
static fr_sbuff_err_t char ** out
Definition value.h:1061
static fr_sbuff_err_t char size_t * len
Definition value.h:1061