1 /* Generate buffers of random data.
2
3 Copyright (C) 2006-2023 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18 /* Written by Paul Eggert. */
19
20 /* FIXME: Improve performance by adding support for the RDRAND machine
21 instruction if available (e.g., Ivy Bridge processors). */
22
23 #include <config.h>
24
25 #include "randread.h"
26
27 #include <errno.h>
28 #include <error.h>
29 #include <exitfail.h>
30 #include <fcntl.h>
31 #include <quote.h>
32 #include <stdint.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/random.h>
37
38 #include "gettext.h"
39 #define _(msgid) gettext (msgid)
40
41 #include "assure.h"
42 #include "minmax.h"
43 #include "rand-isaac.h"
44 #include "stdio-safer.h"
45 #include "unlocked-io.h"
46 #include "xalloc.h"
47
48 #if _STRING_ARCH_unaligned || _STRING_INLINE_unaligned
49 # define ALIGNED_POINTER(ptr, type) true
50 #else
51 # define ALIGNED_POINTER(ptr, type) ((size_t) (ptr) % alignof (type) == 0)
52 #endif
53
54 /* The maximum buffer size used for reads of random data. Using the
55 value 2 * ISAAC_BYTES makes this the largest power of two that
56 would not otherwise cause struct randread_source to grow. */
57 #define RANDREAD_BUFFER_SIZE (2 * ISAAC_BYTES)
58
59 /* A source of random data for generating random buffers. */
60 struct randread_source
61 {
62 /* Stream to read random bytes from. If null, the current
63 implementation uses an internal PRNG (ISAAC). */
64 FILE *source;
65
66 /* Function to call, and its argument, if there is an input error or
67 end of file when reading from the stream; errno is nonzero if
68 there was an error. If this function returns, it should fix the
69 problem before returning. The default handler assumes that
70 handler_arg is the file name of the source. */
71 void (*handler) (void const *);
72 void const *handler_arg;
73
74 /* The buffer for SOURCE. It's kept here to simplify storage
75 allocation and to make it easier to clear out buffered random
76 data. */
77 union
78 {
79 /* The stream buffer, if SOURCE is not null. */
80 char c[RANDREAD_BUFFER_SIZE];
81
82 /* The buffered ISAAC pseudorandom buffer, if SOURCE is null. */
83 struct isaac
84 {
85 /* The number of bytes that are buffered at the end of data.b. */
86 size_t buffered;
87
88 /* State of the ISAAC generator. */
89 struct isaac_state state;
90
91 /* Up to a buffer's worth of pseudorandom data. */
92 union
93 {
94 isaac_word w[ISAAC_WORDS];
95 unsigned char b[ISAAC_BYTES];
96 } data;
97 } isaac;
98 } buf;
99 };
100
101
102 /* The default error handler. */
103
104 static void
randread_error(void const * file_name)105 randread_error (void const *file_name)
106 {
107 affirm (exit_failure);
108 error (exit_failure, errno,
109 errno == 0 ? _("%s: end of file") : _("%s: read error"),
110 quote (file_name));
111 }
112
113 /* Simply return a new randread_source object with the default error
114 handler. */
115
116 static struct randread_source *
simple_new(FILE * source,void const * handler_arg)117 simple_new (FILE *source, void const *handler_arg)
118 {
119 struct randread_source *s = xmalloc (sizeof *s);
120 s->source = source;
121 s->handler = randread_error;
122 s->handler_arg = handler_arg;
123 return s;
124 }
125
126 /* Put a nonce value into BUFFER, with size BUFSIZE.
127 Return true on success, false (setting errno) on failure. */
128
129 static bool
get_nonce(void * buffer,size_t bufsize)130 get_nonce (void *buffer, size_t bufsize)
131 {
132 char *buf = buffer, *buflim = buf + bufsize;
133 while (buf < buflim)
134 {
135 #if defined __sun
136 # define MAX_GETRANDOM 1024
137 #else
138 # define MAX_GETRANDOM SIZE_MAX
139 #endif
140 size_t max_bytes = MIN (buflim - buf, MAX_GETRANDOM);
141 ssize_t nbytes = getrandom (buf, max_bytes, 0);
142 if (0 <= nbytes)
143 buf += nbytes;
144 else if (errno != EINTR)
145 return false;
146 }
147 return true;
148 }
149
150 /* Body of randread_free, broken out to pacify gcc -Wmismatched-dealloc. */
151
152 static int
randread_free_body(struct randread_source * s)153 randread_free_body (struct randread_source *s)
154 {
155 FILE *source = s->source;
156 explicit_bzero (s, sizeof *s);
157 free (s);
158 return source ? fclose (source) : 0;
159 }
160
161 /* Create and initialize a random data source from NAME, or use a
162 reasonable default source if NAME is null. BYTES_BOUND is an upper
163 bound on the number of bytes that will be needed. If zero, it is a
164 hard bound; otherwise it is just an estimate.
165
166 If NAME is not null, NAME is saved for use as the argument of the
167 default handler. Unless a non-default handler is used, NAME's
168 lifetime should be at least that of the returned value.
169
170 Return nullptr (setting errno) on failure. */
171
172 struct randread_source *
randread_new(char const * name,size_t bytes_bound)173 randread_new (char const *name, size_t bytes_bound)
174 {
175 if (bytes_bound == 0)
176 return simple_new (nullptr, nullptr);
177 else
178 {
179 FILE *source = nullptr;
180 struct randread_source *s;
181
182 if (name)
183 if (! (source = fopen_safer (name, "rb")))
184 return nullptr;
185
186 s = simple_new (source, name);
187
188 if (source)
189 setvbuf (source, s->buf.c, _IOFBF, MIN (sizeof s->buf.c, bytes_bound));
190 else
191 {
192 s->buf.isaac.buffered = 0;
193 if (! get_nonce (s->buf.isaac.state.m,
194 MIN (sizeof s->buf.isaac.state.m, bytes_bound)))
195 {
196 int e = errno;
197 randread_free_body (s);
198 errno = e;
199 return nullptr;
200 }
201 isaac_seed (&s->buf.isaac.state);
202 }
203
204 return s;
205 }
206 }
207
208
209 /* Set S's handler and its argument. HANDLER (HANDLER_ARG) is called
210 when there is a read error or end of file from the random data
211 source; errno is nonzero if there was an error. If HANDLER
212 returns, it should fix the problem before returning. The default
213 handler assumes that handler_arg is the file name of the source; it
214 does not return. */
215
216 void
randread_set_handler(struct randread_source * s,void (* handler)(void const *))217 randread_set_handler (struct randread_source *s, void (*handler) (void const *))
218 {
219 s->handler = handler;
220 }
221
222 void
randread_set_handler_arg(struct randread_source * s,void const * handler_arg)223 randread_set_handler_arg (struct randread_source *s, void const *handler_arg)
224 {
225 s->handler_arg = handler_arg;
226 }
227
228
229 /* Place SIZE random bytes into the buffer beginning at P, using
230 the stream in S. */
231
232 static void
readsource(struct randread_source * s,unsigned char * p,size_t size)233 readsource (struct randread_source *s, unsigned char *p, size_t size)
234 {
235 while (true)
236 {
237 size_t inbytes = fread (p, sizeof *p, size, s->source);
238 int fread_errno = errno;
239 p += inbytes;
240 size -= inbytes;
241 if (size == 0)
242 break;
243 errno = (ferror (s->source) ? fread_errno : 0);
244 s->handler (s->handler_arg);
245 }
246 }
247
248
249 /* Place SIZE pseudorandom bytes into the buffer beginning at P, using
250 the buffered ISAAC generator in ISAAC. */
251
252 static void
readisaac(struct isaac * isaac,void * p,size_t size)253 readisaac (struct isaac *isaac, void *p, size_t size)
254 {
255 size_t inbytes = isaac->buffered;
256
257 while (true)
258 {
259 char *char_p = p;
260
261 if (size <= inbytes)
262 {
263 memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, size);
264 isaac->buffered = inbytes - size;
265 return;
266 }
267
268 memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, inbytes);
269 p = char_p + inbytes;
270 size -= inbytes;
271
272 /* If P is aligned, write to *P directly to avoid the overhead
273 of copying from the buffer. */
274 if (ALIGNED_POINTER (p, isaac_word))
275 {
276 isaac_word *wp = p;
277 while (ISAAC_BYTES <= size)
278 {
279 isaac_refill (&isaac->state, wp);
280 wp += ISAAC_WORDS;
281 size -= ISAAC_BYTES;
282 if (size == 0)
283 {
284 isaac->buffered = 0;
285 return;
286 }
287 }
288 p = wp;
289 }
290
291 isaac_refill (&isaac->state, isaac->data.w);
292 inbytes = ISAAC_BYTES;
293 }
294 }
295
296
297 /* Consume random data from *S to generate a random buffer BUF of size
298 SIZE. */
299
300 void
randread(struct randread_source * s,void * buf,size_t size)301 randread (struct randread_source *s, void *buf, size_t size)
302 {
303 if (s->source)
304 readsource (s, buf, size);
305 else
306 readisaac (&s->buf.isaac, buf, size);
307 }
308
309
310 /* Clear *S so that it no longer contains undelivered random data, and
311 deallocate any system resources associated with *S. Return 0 if
312 successful, a negative number (setting errno) if not (this is rare,
313 but can occur in theory if there is an input error). */
314
315 int
randread_free(struct randread_source * s)316 randread_free (struct randread_source *s)
317 {
318 return randread_free_body (s);
319 }
320