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: 53d17290f509aa100f98509181d11143fd590fab $")
24
25#include <freeradius-devel/util/rand.h>
26#include <freeradius-devel/util/hash.h>
27
28#include <fcntl.h>
29#include <stdbool.h>
30
31static _Thread_local fr_randctx fr_rand_pool; //!< A pool of pre-generated random integers
32static _Thread_local bool fr_rand_initialized = false;
33
34void fr_rand_init(void)
35{
36 int fd;
38 uint8_t *end = p + sizeof(fr_rand_pool.randrsl);
39
40 if (fr_rand_initialized) return;
41
42
43 memset(&fr_rand_pool, 0, sizeof(fr_rand_pool));
44
45 fd = open("/dev/urandom", O_RDONLY);
46 if (fd >= 0) {
47 ssize_t rcode;
48
49 while (p < end) {
50 rcode = read(fd, p, (size_t) (end - p));
51 if ((rcode < 0) && (errno != EINTR)) break;
52 if (rcode > 0) p += rcode;
53 }
54 close(fd);
55 } else {
56 /*
57 * We use unix_time, because fr_time() is
58 * nanoseconds since the server started.
59 * Which is likely a very small number.
60 * Whereas unix time is somewhat more
61 * unknown. If we're not seeding off of
62 * /dev/urandom, then any randomness we
63 * get here is terrible.
64 */
66
67 memcpy((void *) &fr_rand_pool.randrsl[0], &when, sizeof(when));
68 }
69
73}
74
75/** Mix data into the random number generator.
76 *
77 * May be called any number of times.
78 */
79void fr_rand_mixin(void const *data, size_t size)
80{
82
83 /*
84 * Ensure that the pool is initialized.
85 */
88 }
89
90 /*
91 * Hash the user data
92 */
93 hash = fr_rand();
94 if (!hash) hash = fr_rand();
95 hash = fr_hash_update(data, size, hash);
96
98}
99
100
101/** Return a 32-bit random number
102 *
103 * @hidecallergraph
104 */
106{
107 uint32_t num;
108
109 /*
110 * Ensure that the pool is initialized.
111 */
112 if (!fr_rand_initialized) {
113 fr_rand_init();
114 }
115
117 if (fr_rand_pool.randcnt >= 256) {
120 }
121
122 return num;
123}
124
125void fr_rand_buffer(void *start, size_t length)
126{
127 uint32_t x;
128 uint8_t *buffer = start;
129 size_t buflen = length;
130
131 if (buflen > 4) {
132 size_t i;
133
134 for (i = 0; i < buflen; i += 4) {
135 x = fr_rand();
136 memcpy(buffer + i, &x, sizeof(x));
137 }
138
139 /*
140 * Keep only the last bytes in the word.
141 */
142 i = buflen & ~0x03;
143 buffer += i;
144 buflen &= 0x03;
145 }
146
147 if (!buflen) return;
148
149 x = fr_rand();
150
151 memcpy(buffer, &x, buflen);
152}
153
154/** Generate a random string
155 *
156 * @note Character selection is not perfectly distributed, should not be used
157 * for cryptographic purposes.
158 *
159 * @param[out] out Where to write the string
160 * @param[in] len Length of the output buffer.
161 * @param[in] class to pick characters from (see function body).
162 */
163void fr_rand_str(uint8_t *out, size_t len, char class)
164{
165 uint8_t *p = out, *end = p + len;
166 unsigned int word, mod;
167 uint8_t byte;
168
169 /*
170 * Lookup tables for randstr char classes
171 */
172 static char randstr_punc[] = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
173 static char randstr_salt[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz/.";
174
175 /*
176 * Characters humans rarely confuse. Reduces char set considerably
177 * should only be used for things such as one time passwords.
178 */
179 static char randstr_otp[] = "469ACGHJKLMNPQRUVWXYabdfhijkprstuvwxyz";
180
181/*
182 * yeah yeah not perfect distribution
183 * but close enough.
184 */
185#define fill(_expr) do { \
186while (p < end) { \
187 if ((mod = ((p - out) & (sizeof(word) - 1))) == 0) word = fr_rand(); \
188 byte = ((uint8_t *)&word)[mod]; \
189 *p++ = (_expr); \
190} } while (0)
191
192 switch (class) {
193 /*
194 * Lowercase letters
195 */
196 case 'c':
197 fill('a' + (byte % 26));
198 return;
199
200 /*
201 * Uppercase letters
202 */
203 case 'C':
204 fill('A' + (byte % 26));
205 return;
206
207 /*
208 * Numbers
209 */
210 case 'n':
211 fill('0' + (byte % 10));
212 return;
213
214 /*
215 * Alpha numeric
216 */
217 case 'a':
218 fill(randstr_salt[byte % (sizeof(randstr_salt) - 3)]);
219 return;
220
221 /*
222 * Punctuation
223 */
224 case '!':
225 fill(randstr_punc[byte % (sizeof(randstr_punc) - 1)]);
226 return;
227
228 /*
229 * Alpha numeric + punctuation
230 */
231 case '.':
232 fill('!' + (byte % 95));
233 break;
234
235 /*
236 * Alpha numeric + salt chars './'
237 */
238 case 's':
239 fill(randstr_salt[byte % (sizeof(randstr_salt) - 1)]);
240 break;
241
242 /*
243 * Chars suitable for One Time Password tokens.
244 * Alpha numeric with easily confused char pairs removed.
245 */
246 case 'o':
247 fill(randstr_otp[byte % (sizeof(randstr_otp) - 1)]);
248 break;
249
250 /*
251 * Binary data
252 */
253 case 'b':
254 default:
255 fill(byte);
256 return;
257 }
258}
259
260
261/*
262 * http://www.cse.yorku.ca/~oz/marsaglia-rng.html
263 *
264 * We implement MWC here, which uses 2 32-bit numbers for a
265 * state, and has a period of 2^60.
266 *
267 * We could extend this to a larger RNG with 4 32-bit state
268 * numbers {a, b, c, d} and use KISS, which has a period of about
269 * 2^123.
270 *
271 * a' = 36969 * (a & 65535) + (a >> 16)
272 * b' = 18000 * (b & 65535) + (b >> 16))
273 *
274 * MWC (a' << 16) + b'
275 * SHR3 (c ^= (c <<17); c ^= ( c>>13); c ^= (c << 5))
276 * CONG d' = 69069 * d + 1234567
277 * KISS ((MWC^CONG)+SHR3)
278 */
280{
281 ctx->a = (36969 * (ctx->a & 0xffff)) + (ctx->a >> 16);
282 ctx->b = (18000 * (ctx->b & 0xffff)) + (ctx->b >> 16);
283
284 return (ctx->a << 16) + ctx->b;
285}
static int const char char buffer[256]
Definition acutest.h:576
#define RCSID(id)
Definition build.h:483
uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
Definition hash.c:846
void fr_isaac_init(fr_randctx *ctx, int flag)
Definition isaac.c:85
void fr_isaac(fr_randctx *ctx)
Definition isaac.c:46
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:31
uint32_t fr_fast_rand(fr_fast_rand_t *ctx)
Definition rand.c:279
void fr_rand_init(void)
Definition rand.c:34
static _Thread_local bool fr_rand_initialized
Definition rand.c:32
void fr_rand_str(uint8_t *out, size_t len, char class)
Generate a random string.
Definition rand.c:163
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:105
void fr_rand_buffer(void *start, size_t length)
Definition rand.c:125
void fr_rand_mixin(void const *data, size_t size)
Mix data into the random number generator.
Definition rand.c:79
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
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
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
close(uq->fd)
static fr_slen_t data
Definition value.h:1265
static size_t char ** out
Definition value.h:997