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