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