aboutsummaryrefslogtreecommitdiff
path: root/src/crypto/random.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/random.c')
-rw-r--r--src/crypto/random.c62
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