aboutsummaryrefslogtreecommitdiff
path: root/src/platform/posix/posix_rand.c
blob: 4322e49159988791a130a9a154f6a73a9f09eac4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//
// Copyright 2017 Garrett D'Amore <garrett@damore.org>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt).  A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//

// POSIX clock stuff.
#include "core/nng_impl.h"

#ifdef PLATFORM_POSIX_RANDOM

#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <time.h>
#include <unistd.h>

#ifdef NNG_USE_GETRANDOM
#include <linux/random.h>
#endif

#ifdef NNG_USE_GETENTROPY
#include <sys/random.h>
#endif

// This structure represents the very barest minimum that we can use as
// a source of entropy.  We mix these into our initial entropy, but really
// really really you want to have more data than this available, especially
// for cryptographic applications.
struct nni_plat_prng_x {
	nni_time       now;
	pid_t          pid;
	uid_t          uid;
	struct utsname uts;
};

void
nni_plat_seed_prng(void *buf, size_t bufsz)
{
	struct nni_plat_prng_x x;
	int                    i;

	memset(buf, 0, bufsz);

#if defined(NNG_USE_GETRANDOM)
	// Latest Linux has a nice API here.
	(void) getrandom(buf, bufsz, 0);
#elif defined(NNG_USE_GETENTROPY)
	// Modern BSD systems prefer this, but can only generate 256 bytes
	(void) getentropy(buf, bufsz > 256 ? 256 : 0);
#elif defined(NNG_USE_ARC4RANDOM)
	// This uses BSD style pRNG seeded from the kernel in libc.
	(void) arc4random_buf(buf, bufsz);
#elif defined(NNG_USE_DEVURANDOM)
	// The historic /dev/urandom device.  This is not as a good as
	// a system call, since file descriptor attacks are possible,
	// and it may need special permissions.  We choose /dev/urandom
	// over /dev/random to avoid diminishing the system entropy.
	int fd;

	if ((fd = open("/dev/urandom", O_RDONLY)) >= 0) {
		(void) read(fd, buf, bufsz);
		(void) close(fd);
	}
#endif

	// As a speical extra guard, let's mixin the data from the
	// following system calls.  This ensures that even on the most
	// limited of systems, we have at least *some* level of randomness.
	// The mixing is done in a way to avoid diminishing entropy we may
	// have already collected.
	memset(&x, 0, sizeof(x)); // satisfy valgrind
	x.now = nni_clock();
	x.pid = getpid();
	x.uid = getuid();
	uname(&x.uts);

	for (i = 0; (i < bufsz) && (i < sizeof(x)); i++) {
		((uint8_t *) buf)[i] ^= ((uint8_t *) &x)[i];
	}
}

#else

// Suppress empty symbols warnings in ranlib.
int nni_posix_rand_not_used = 0;

#endif // PLATFORM_POSIX_RANDOM