diff options
Diffstat (limited to 'src/crypto/random.c')
-rw-r--r-- | src/crypto/random.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/src/crypto/random.c b/src/crypto/random.c new file mode 100644 index 000000000..582d0b8f6 --- /dev/null +++ b/src/crypto/random.c @@ -0,0 +1,62 @@ +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "hash.h" +#include "random.h" + +static void generate_system_random_bytes(size_t n, void *result) { + int fd; + if ((fd = open("/dev/urandom", O_RDONLY | O_NOCTTY | O_CLOEXEC)) < 0) { + err(EXIT_FAILURE, "open /dev/urandom"); + } + for (;;) { + ssize_t res = read(fd, result, n); + if ((size_t) res == n) { + break; + } + if (res < 0) { + if (errno != EINTR) { + err(EXIT_FAILURE, "read /dev/urandom"); + } + } else if (res == 0) { + errx(EXIT_FAILURE, "read /dev/urandom: end of file"); + } else { + result = padd(result, (size_t) res); + n -= (size_t) res; + } + } + if (close(fd) < 0) { + err(EXIT_FAILURE, "close /dev/urandom"); + } +} + +static struct keccak_state state; + +void init_random(void) { + generate_system_random_bytes(32, &state); +} + +void generate_random_bytes(size_t n, void *result) { + if (n == 0) { + return; + } + for (;;) { + keccak_permutation(&state); + if (n <= HASH_DATA_AREA) { + memcpy(result, &state, n); + return; + } else { + memcpy(result, &state, HASH_DATA_AREA); + result = padd(result, HASH_DATA_AREA); + n -= HASH_DATA_AREA; + } + } +}
\ No newline at end of file |