The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 281ac1f18124554c97f9306670a25b68a6757b70 $")
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
31static _Thread_local bool fr_rand_initialized = false;
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/** Mix data into the random number generator.
75 *
76 * May be called any number of times.
77 */
78void fr_rand_mixin(void const *data, size_t size)
79{
81
82 /*
83 * Ensure that the pool is initialized.
84 */
87 }
88
89 /*
90 * Hash the user data
91 */
92 hash = fr_rand();
93 if (!hash) hash = fr_rand();
94 hash = fr_hash_update(data, size, hash);
95
97}
98
99
100/** Return a 32-bit random number
101 *
102 * @hidecallergraph
103 */
105{
106 uint32_t num;
107
108 /*
109 * Ensure that the pool is initialized.
110 */
111 if (!fr_rand_initialized) {
112 fr_rand_init();
113 }
114
116 if (fr_rand_pool.randcnt >= 256) {
119 }
120
121 return num;
122}
123
124void fr_rand_buffer(void *start, size_t length)
125{
126 uint32_t x;
127 uint8_t *buffer = start;
128 size_t buflen = length;
129
130 if (buflen > 4) {
131 size_t i;
132
133 for (i = 0; i <= (buflen - 4); i += 4) {
134 x = fr_rand();
135 memcpy(buffer + i, &x, sizeof(x));
136 }
137
138 /*
139 * Keep only the last bytes in the word.
140 */
141 i = buflen & ~0x03;
142 buffer += i;
143 buflen &= 0x03;
144 }
145
146 if (!buflen) return;
147
148 x = fr_rand();
149
150 memcpy(buffer, &x, buflen);
151}
152
153/** Generate a random string
154 *
155 * @note Character selection is not perfectly distributed, should not be used
156 * for cryptographic purposes.
157 *
158 * @param[out] out Where to write the string
159 * @param[in] len Length of the output buffer.
160 * @param[in] class to pick characters from (see function body).
161 */
162void fr_rand_str(uint8_t *out, size_t len, char class)
163{
164 uint8_t *p = out, *end = p + len;
165 unsigned int word, mod;
166 uint8_t byte;
167
168 /*
169 * Lookup tables for randstr char classes
170 */
171 static char randstr_punc[] = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
172 static char randstr_salt[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz/.";
173
174 /*
175 * Characters humans rarely confuse. Reduces char set considerably
176 * should only be used for things such as one time passwords.
177 */
178 static char randstr_otp[] = "469ACGHJKLMNPQRUVWXYabdfhijkprstuvwxyz";
179
180/*
181 * yeah yeah not perfect distribution
182 * but close enough.
183 */
184#define fill(_expr) do { \
185while (p < end) { \
186 if ((mod = ((p - out) & (sizeof(word) - 1))) == 0) word = fr_rand(); \
187 byte = ((uint8_t *)&word)[mod]; \
188 *p++ = (_expr); \
189} } while (0)
190
191 switch (class) {
192 /*
193 * Lowercase letters
194 */
195 case 'c':
196 fill('a' + (byte % 26));
197 return;
198
199 /*
200 * Uppercase letters
201 */
202 case 'C':
203 fill('A' + (byte % 26));
204 return;
205
206 /*
207 * Numbers
208 */
209 case 'n':
210 fill('0' + (byte % 10));
211 return;
212
213 /*
214 * Alpha numeric
215 */
216 case 'a':
217 fill(randstr_salt[byte % (sizeof(randstr_salt) - 3)]);
218 return;
219
220 /*
221 * Punctuation
222 */
223 case '!':
224 fill(randstr_punc[byte % (sizeof(randstr_punc) - 1)]);
225 return;
226
227 /*
228 * Alpha numeric + punctuation
229 */
230 case '.':
231 fill('!' + (byte % 95));
232 break;
233
234 /*
235 * Alpha numeric + salt chars './'
236 */
237 case 's':
238 fill(randstr_salt[byte % (sizeof(randstr_salt) - 1)]);
239 break;
240
241 /*
242 * Chars suitable for One Time Password tokens.
243 * Alpha numeric with easily confused char pairs removed.
244 */
245 case 'o':
246 fill(randstr_otp[byte % (sizeof(randstr_otp) - 1)]);
247 break;
248
249 /*
250 * Binary data
251 */
252 case 'b':
253 default:
254 fill(byte);
255 return;
256 }
257}
258
259
260/*
261 * http://www.cse.yorku.ca/~oz/marsaglia-rng.html
262 *
263 * We implement MWC here, which uses 2 32-bit numbers for a
264 * state, and has a period of 2^60.
265 *
266 * We could extend this to a larger RNG with 4 32-bit state
267 * numbers {a, b, c, d} and use KISS, which has a period of about
268 * 2^123.
269 *
270 * a' = 36969 * (a & 65535) + (a >> 16)
271 * b' = 18000 * (b & 65535) + (b >> 16))
272 *
273 * MWC (a' << 16) + b'
274 * SHR3 (c ^= (c <<17); c ^= ( c>>13); c ^= (c << 5))
275 * CONG d' = 69069 * d + 1234567
276 * KISS ((MWC^CONG)+SHR3)
277 */
279{
280 ctx->a = (36969 * (ctx->a & 0xffff)) + (ctx->a >> 16);
281 ctx->b = (18000 * (ctx->b & 0xffff)) + (ctx->b >> 16);
282
283 return (ctx->a << 16) + ctx->b;
284}
static int const char char buffer[256]
Definition acutest.h:576
#define RCSID(id)
Definition build.h:506
uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
Definition hash.c:881
void fr_isaac_init(fr_randctx *ctx, int flag)
Definition isaac.c:85
void fr_isaac(fr_randctx *ctx)
Definition isaac.c:46
#define fr_time()
Definition event.c:60
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
#define fill(_expr)
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:278
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:162
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:104
void fr_rand_buffer(void *start, size_t length)
Definition rand.c:124
void fr_rand_mixin(void const *data, size_t size)
Mix data into the random number generator.
Definition rand.c:78
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:1340
static size_t char ** out
Definition value.h:1030