| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
|
|
| |
| |
|
|
| #include <config.h> |
|
|
| #include "randread.h" |
|
|
| #include <errno.h> |
| #include <error.h> |
| #include <exitfail.h> |
| #include <fcntl.h> |
| #include <quote.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/random.h> |
|
|
| #include "gettext.h" |
| #define _(msgid) gettext (msgid) |
|
|
| #include "assure.h" |
| #include "minmax.h" |
| #include "rand-isaac.h" |
| #include "stdio-safer.h" |
| #include "unlocked-io.h" |
| #include "xalloc.h" |
|
|
| #if _STRING_ARCH_unaligned || _STRING_INLINE_unaligned |
| # define POINTER_IS_ALIGNED(ptr, type) true |
| #else |
| # define POINTER_IS_ALIGNED(ptr, type) ((size_t) (ptr) % alignof (type) == 0) |
| #endif |
|
|
| |
| |
| |
| #define RANDREAD_BUFFER_SIZE (2 * ISAAC_BYTES) |
|
|
| |
| struct randread_source |
| { |
| |
| |
| FILE *source; |
|
|
| |
| |
| |
| |
| |
| void (*handler) (void const *); |
| void const *handler_arg; |
|
|
| |
| |
| |
| union |
| { |
| |
| char c[RANDREAD_BUFFER_SIZE]; |
|
|
| |
| struct isaac |
| { |
| |
| size_t buffered; |
|
|
| |
| struct isaac_state state; |
|
|
| |
| union |
| { |
| isaac_word w[ISAAC_WORDS]; |
| unsigned char b[ISAAC_BYTES]; |
| } data; |
| } isaac; |
| } buf; |
| }; |
|
|
|
|
| |
|
|
| static void |
| randread_error (void const *file_name) |
| { |
| affirm (exit_failure); |
| error (exit_failure, errno, |
| errno == 0 ? _("%s: end of file") : _("%s: read error"), |
| quote (file_name)); |
| } |
|
|
| |
| |
|
|
| static struct randread_source * |
| simple_new (FILE *source, void const *handler_arg) |
| { |
| struct randread_source *s = xmalloc (sizeof *s); |
| s->source = source; |
| s->handler = randread_error; |
| s->handler_arg = handler_arg; |
| return s; |
| } |
|
|
| |
| |
|
|
| static bool |
| get_nonce (void *buffer, size_t bufsize) |
| { |
| char *buf = buffer, *buflim = buf + bufsize; |
| while (buf < buflim) |
| { |
| #if defined __sun |
| # define MAX_GETRANDOM 1024 |
| #else |
| # define MAX_GETRANDOM SIZE_MAX |
| #endif |
| size_t max_bytes = MIN (buflim - buf, MAX_GETRANDOM); |
| ssize_t nbytes = getrandom (buf, max_bytes, 0); |
| if (0 <= nbytes) |
| buf += nbytes; |
| else if (errno != EINTR) |
| return false; |
| } |
| return true; |
| } |
|
|
| |
|
|
| static int |
| randread_free_body (struct randread_source *s) |
| { |
| FILE *source = s->source; |
| explicit_bzero (s, sizeof *s); |
| free (s); |
| return source ? fclose (source) : 0; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| struct randread_source * |
| randread_new (char const *name, size_t bytes_bound) |
| { |
| if (bytes_bound == 0) |
| return simple_new (nullptr, nullptr); |
| else |
| { |
| FILE *source = nullptr; |
| struct randread_source *s; |
|
|
| if (name) |
| if (! (source = fopen_safer (name, "rb"))) |
| return nullptr; |
|
|
| s = simple_new (source, name); |
|
|
| if (source) |
| setvbuf (source, s->buf.c, _IOFBF, MIN (sizeof s->buf.c, bytes_bound)); |
| else |
| { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| s->buf.isaac.buffered = 0; |
| if (! get_nonce (s->buf.isaac.state.m, |
| sizeof s->buf.isaac.state.m)) |
| { |
| int e = errno; |
| randread_free_body (s); |
| errno = e; |
| return nullptr; |
| } |
| isaac_seed (&s->buf.isaac.state); |
| } |
|
|
| return s; |
| } |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| |
|
|
| void |
| randread_set_handler (struct randread_source *s, void (*handler) (void const *)) |
| { |
| s->handler = handler; |
| } |
|
|
| void |
| randread_set_handler_arg (struct randread_source *s, void const *handler_arg) |
| { |
| s->handler_arg = handler_arg; |
| } |
|
|
|
|
| |
| |
|
|
| static void |
| readsource (struct randread_source *s, unsigned char *p, size_t size) |
| { |
| while (true) |
| { |
| size_t inbytes = fread (p, sizeof *p, size, s->source); |
| int fread_errno = errno; |
| p += inbytes; |
| size -= inbytes; |
| if (size == 0) |
| break; |
| errno = (ferror (s->source) ? fread_errno : 0); |
| s->handler (s->handler_arg); |
| } |
| } |
|
|
|
|
| |
| |
|
|
| static void |
| readisaac (struct isaac *isaac, void *p, size_t size) |
| { |
| size_t inbytes = isaac->buffered; |
|
|
| while (true) |
| { |
| char *char_p = p; |
|
|
| if (size <= inbytes) |
| { |
| memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, size); |
| isaac->buffered = inbytes - size; |
| return; |
| } |
|
|
| memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, inbytes); |
| p = char_p + inbytes; |
| size -= inbytes; |
|
|
| |
| |
| if (POINTER_IS_ALIGNED (p, isaac_word)) |
| { |
| isaac_word *wp = p; |
| while (ISAAC_BYTES <= size) |
| { |
| isaac_refill (&isaac->state, wp); |
| wp += ISAAC_WORDS; |
| size -= ISAAC_BYTES; |
| if (size == 0) |
| { |
| isaac->buffered = 0; |
| return; |
| } |
| } |
| p = wp; |
| } |
|
|
| isaac_refill (&isaac->state, isaac->data.w); |
| inbytes = ISAAC_BYTES; |
| } |
| } |
|
|
|
|
| |
| |
|
|
| void |
| randread (struct randread_source *s, void *buf, size_t size) |
| { |
| if (s->source) |
| readsource (s, buf, size); |
| else |
| readisaac (&s->buf.isaac, buf, size); |
| } |
|
|
|
|
| |
| |
| |
| |
|
|
| int |
| randread_free (struct randread_source *s) |
| { |
| return randread_free_body (s); |
| } |
|
|