1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * Random number generator
3e5b75505Sopenharmony_ci * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci *
8e5b75505Sopenharmony_ci * This random number generator is used to provide additional entropy to the
9e5b75505Sopenharmony_ci * one provided by the operating system (os_get_random()) for session key
10e5b75505Sopenharmony_ci * generation. The os_get_random() output is expected to be secure and the
11e5b75505Sopenharmony_ci * implementation here is expected to provide only limited protection against
12e5b75505Sopenharmony_ci * cases where os_get_random() cannot provide strong randomness. This
13e5b75505Sopenharmony_ci * implementation shall not be assumed to be secure as the sole source of
14e5b75505Sopenharmony_ci * randomness. The random_get_bytes() function mixes in randomness from
15e5b75505Sopenharmony_ci * os_get_random() and as such, calls to os_get_random() can be replaced with
16e5b75505Sopenharmony_ci * calls to random_get_bytes() without reducing security.
17e5b75505Sopenharmony_ci *
18e5b75505Sopenharmony_ci * The design here follows partially the design used in the Linux
19e5b75505Sopenharmony_ci * drivers/char/random.c, but the implementation here is simpler and not as
20e5b75505Sopenharmony_ci * strong. This is a compromise to reduce duplicated CPU effort and to avoid
21e5b75505Sopenharmony_ci * extra code/memory size. As pointed out above, os_get_random() needs to be
22e5b75505Sopenharmony_ci * guaranteed to be secure for any of the security assumptions to hold.
23e5b75505Sopenharmony_ci */
24e5b75505Sopenharmony_ci
25e5b75505Sopenharmony_ci#include "utils/includes.h"
26e5b75505Sopenharmony_ci#ifdef __linux__
27e5b75505Sopenharmony_ci#include <fcntl.h>
28e5b75505Sopenharmony_ci#ifdef CONFIG_GETRANDOM
29e5b75505Sopenharmony_ci#include <sys/random.h>
30e5b75505Sopenharmony_ci#endif /* CONFIG_GETRANDOM */
31e5b75505Sopenharmony_ci#endif /* __linux__ */
32e5b75505Sopenharmony_ci#include <stdlib.h>
33e5b75505Sopenharmony_ci
34e5b75505Sopenharmony_ci#include "utils/common.h"
35e5b75505Sopenharmony_ci#include "utils/eloop.h"
36e5b75505Sopenharmony_ci#include "crypto/crypto.h"
37e5b75505Sopenharmony_ci#include "sha1.h"
38e5b75505Sopenharmony_ci#include "random.h"
39e5b75505Sopenharmony_ci
40e5b75505Sopenharmony_ci#define POOL_WORDS 32
41e5b75505Sopenharmony_ci#define POOL_WORDS_MASK (POOL_WORDS - 1)
42e5b75505Sopenharmony_ci#define POOL_TAP1 26
43e5b75505Sopenharmony_ci#define POOL_TAP2 20
44e5b75505Sopenharmony_ci#define POOL_TAP3 14
45e5b75505Sopenharmony_ci#define POOL_TAP4 7
46e5b75505Sopenharmony_ci#define POOL_TAP5 1
47e5b75505Sopenharmony_ci#define EXTRACT_LEN 16
48e5b75505Sopenharmony_ci#define MIN_READY_MARK 2
49e5b75505Sopenharmony_ci
50e5b75505Sopenharmony_cistatic u32 pool[POOL_WORDS];
51e5b75505Sopenharmony_cistatic unsigned int input_rotate = 0;
52e5b75505Sopenharmony_cistatic unsigned int pool_pos = 0;
53e5b75505Sopenharmony_cistatic u8 dummy_key[20];
54e5b75505Sopenharmony_ci#ifdef __linux__
55e5b75505Sopenharmony_cistatic size_t dummy_key_avail = 0;
56e5b75505Sopenharmony_cistatic int random_fd = -1;
57e5b75505Sopenharmony_ci#endif /* __linux__ */
58e5b75505Sopenharmony_cistatic unsigned int own_pool_ready = 0;
59e5b75505Sopenharmony_ci#define RANDOM_ENTROPY_SIZE 20
60e5b75505Sopenharmony_cistatic char *random_entropy_file = NULL;
61e5b75505Sopenharmony_ci
62e5b75505Sopenharmony_ci#define MIN_COLLECT_ENTROPY 1000
63e5b75505Sopenharmony_cistatic unsigned int entropy = 0;
64e5b75505Sopenharmony_cistatic unsigned int total_collected = 0;
65e5b75505Sopenharmony_ci
66e5b75505Sopenharmony_ci
67e5b75505Sopenharmony_cistatic void random_write_entropy(void);
68e5b75505Sopenharmony_ci
69e5b75505Sopenharmony_ci
70e5b75505Sopenharmony_cistatic u32 __ROL32(u32 x, u32 y)
71e5b75505Sopenharmony_ci{
72e5b75505Sopenharmony_ci	if (y == 0)
73e5b75505Sopenharmony_ci		return x;
74e5b75505Sopenharmony_ci
75e5b75505Sopenharmony_ci	return (x << (y & 31)) | (x >> (32 - (y & 31)));
76e5b75505Sopenharmony_ci}
77e5b75505Sopenharmony_ci
78e5b75505Sopenharmony_ci
79e5b75505Sopenharmony_cistatic void random_mix_pool(const void *buf, size_t len)
80e5b75505Sopenharmony_ci{
81e5b75505Sopenharmony_ci	static const u32 twist[8] = {
82e5b75505Sopenharmony_ci		0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
83e5b75505Sopenharmony_ci		0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278
84e5b75505Sopenharmony_ci	};
85e5b75505Sopenharmony_ci	const u8 *pos = buf;
86e5b75505Sopenharmony_ci	u32 w;
87e5b75505Sopenharmony_ci
88e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_EXCESSIVE, "random_mix_pool", buf, len);
89e5b75505Sopenharmony_ci
90e5b75505Sopenharmony_ci	while (len--) {
91e5b75505Sopenharmony_ci		w = __ROL32(*pos++, input_rotate & 31);
92e5b75505Sopenharmony_ci		input_rotate += pool_pos ? 7 : 14;
93e5b75505Sopenharmony_ci		pool_pos = (pool_pos - 1) & POOL_WORDS_MASK;
94e5b75505Sopenharmony_ci		w ^= pool[pool_pos];
95e5b75505Sopenharmony_ci		w ^= pool[(pool_pos + POOL_TAP1) & POOL_WORDS_MASK];
96e5b75505Sopenharmony_ci		w ^= pool[(pool_pos + POOL_TAP2) & POOL_WORDS_MASK];
97e5b75505Sopenharmony_ci		w ^= pool[(pool_pos + POOL_TAP3) & POOL_WORDS_MASK];
98e5b75505Sopenharmony_ci		w ^= pool[(pool_pos + POOL_TAP4) & POOL_WORDS_MASK];
99e5b75505Sopenharmony_ci		w ^= pool[(pool_pos + POOL_TAP5) & POOL_WORDS_MASK];
100e5b75505Sopenharmony_ci		pool[pool_pos] = (w >> 3) ^ twist[w & 7];
101e5b75505Sopenharmony_ci	}
102e5b75505Sopenharmony_ci}
103e5b75505Sopenharmony_ci
104e5b75505Sopenharmony_ci
105e5b75505Sopenharmony_cistatic void random_extract(u8 *out)
106e5b75505Sopenharmony_ci{
107e5b75505Sopenharmony_ci	unsigned int i;
108e5b75505Sopenharmony_ci	u8 hash[SHA1_MAC_LEN];
109e5b75505Sopenharmony_ci	u32 *hash_ptr;
110e5b75505Sopenharmony_ci	u32 buf[POOL_WORDS / 2];
111e5b75505Sopenharmony_ci
112e5b75505Sopenharmony_ci	/* First, add hash back to pool to make backtracking more difficult. */
113e5b75505Sopenharmony_ci	hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) pool,
114e5b75505Sopenharmony_ci		  sizeof(pool), hash);
115e5b75505Sopenharmony_ci	random_mix_pool(hash, sizeof(hash));
116e5b75505Sopenharmony_ci	/* Hash half the pool to extra data */
117e5b75505Sopenharmony_ci	for (i = 0; i < POOL_WORDS / 2; i++)
118e5b75505Sopenharmony_ci		buf[i] = pool[(pool_pos - i) & POOL_WORDS_MASK];
119e5b75505Sopenharmony_ci	hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) buf,
120e5b75505Sopenharmony_ci		  sizeof(buf), hash);
121e5b75505Sopenharmony_ci	/*
122e5b75505Sopenharmony_ci	 * Fold the hash to further reduce any potential output pattern.
123e5b75505Sopenharmony_ci	 * Though, compromise this to reduce CPU use for the most common output
124e5b75505Sopenharmony_ci	 * length (32) and return 16 bytes from instead of only half.
125e5b75505Sopenharmony_ci	 */
126e5b75505Sopenharmony_ci	hash_ptr = (u32 *) hash;
127e5b75505Sopenharmony_ci	hash_ptr[0] ^= hash_ptr[4];
128e5b75505Sopenharmony_ci	os_memcpy(out, hash, EXTRACT_LEN);
129e5b75505Sopenharmony_ci}
130e5b75505Sopenharmony_ci
131e5b75505Sopenharmony_ci
132e5b75505Sopenharmony_civoid random_add_randomness(const void *buf, size_t len)
133e5b75505Sopenharmony_ci{
134e5b75505Sopenharmony_ci	struct os_time t;
135e5b75505Sopenharmony_ci	static unsigned int count = 0;
136e5b75505Sopenharmony_ci
137e5b75505Sopenharmony_ci	count++;
138e5b75505Sopenharmony_ci	if (entropy > MIN_COLLECT_ENTROPY && (count & 0x3ff) != 0) {
139e5b75505Sopenharmony_ci		/*
140e5b75505Sopenharmony_ci		 * No need to add more entropy at this point, so save CPU and
141e5b75505Sopenharmony_ci		 * skip the update.
142e5b75505Sopenharmony_ci		 */
143e5b75505Sopenharmony_ci		return;
144e5b75505Sopenharmony_ci	}
145e5b75505Sopenharmony_ci	wpa_printf(MSG_EXCESSIVE, "Add randomness: count=%u entropy=%u",
146e5b75505Sopenharmony_ci		   count, entropy);
147e5b75505Sopenharmony_ci
148e5b75505Sopenharmony_ci	os_get_time(&t);
149e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
150e5b75505Sopenharmony_ci			(const u8 *) pool, sizeof(pool));
151e5b75505Sopenharmony_ci	random_mix_pool(&t, sizeof(t));
152e5b75505Sopenharmony_ci	random_mix_pool(buf, len);
153e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
154e5b75505Sopenharmony_ci			(const u8 *) pool, sizeof(pool));
155e5b75505Sopenharmony_ci	entropy++;
156e5b75505Sopenharmony_ci	total_collected++;
157e5b75505Sopenharmony_ci}
158e5b75505Sopenharmony_ci
159e5b75505Sopenharmony_ci
160e5b75505Sopenharmony_ciint random_get_bytes(void *buf, size_t len)
161e5b75505Sopenharmony_ci{
162e5b75505Sopenharmony_ci#ifdef CONFIG_TEST_RANDOM
163e5b75505Sopenharmony_ci    /* Only for test */
164e5b75505Sopenharmony_ci    for (size_t i = 0; i < len; i++) {
165e5b75505Sopenharmony_ci        buf[i] = random();
166e5b75505Sopenharmony_ci    }
167e5b75505Sopenharmony_ci#else /* CONFIG_TEST_RANDOM */
168e5b75505Sopenharmony_ci	int ret;
169e5b75505Sopenharmony_ci	u8 *bytes = buf;
170e5b75505Sopenharmony_ci	size_t left;
171e5b75505Sopenharmony_ci
172e5b75505Sopenharmony_ci	wpa_printf(MSG_MSGDUMP, "Get randomness: len=%u entropy=%u",
173e5b75505Sopenharmony_ci		   (unsigned int) len, entropy);
174e5b75505Sopenharmony_ci
175e5b75505Sopenharmony_ci	/* Start with assumed strong randomness from OS */
176e5b75505Sopenharmony_ci	ret = os_get_random(buf, len);
177e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_EXCESSIVE, "random from os_get_random",
178e5b75505Sopenharmony_ci			buf, len);
179e5b75505Sopenharmony_ci
180e5b75505Sopenharmony_ci	/* Mix in additional entropy extracted from the internal pool */
181e5b75505Sopenharmony_ci	left = len;
182e5b75505Sopenharmony_ci	while (left) {
183e5b75505Sopenharmony_ci		size_t siz, i;
184e5b75505Sopenharmony_ci		u8 tmp[EXTRACT_LEN];
185e5b75505Sopenharmony_ci		random_extract(tmp);
186e5b75505Sopenharmony_ci		wpa_hexdump_key(MSG_EXCESSIVE, "random from internal pool",
187e5b75505Sopenharmony_ci				tmp, sizeof(tmp));
188e5b75505Sopenharmony_ci		siz = left > EXTRACT_LEN ? EXTRACT_LEN : left;
189e5b75505Sopenharmony_ci		for (i = 0; i < siz; i++)
190e5b75505Sopenharmony_ci			*bytes++ ^= tmp[i];
191e5b75505Sopenharmony_ci		left -= siz;
192e5b75505Sopenharmony_ci	}
193e5b75505Sopenharmony_ci
194e5b75505Sopenharmony_ci#ifdef CONFIG_FIPS
195e5b75505Sopenharmony_ci	/* Mix in additional entropy from the crypto module */
196e5b75505Sopenharmony_ci	bytes = buf;
197e5b75505Sopenharmony_ci	left = len;
198e5b75505Sopenharmony_ci	while (left) {
199e5b75505Sopenharmony_ci		size_t siz, i;
200e5b75505Sopenharmony_ci		u8 tmp[EXTRACT_LEN];
201e5b75505Sopenharmony_ci		if (crypto_get_random(tmp, sizeof(tmp)) < 0) {
202e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR, "random: No entropy available "
203e5b75505Sopenharmony_ci				   "for generating strong random bytes");
204e5b75505Sopenharmony_ci			return -1;
205e5b75505Sopenharmony_ci		}
206e5b75505Sopenharmony_ci		wpa_hexdump_key(MSG_EXCESSIVE, "random from crypto module",
207e5b75505Sopenharmony_ci				tmp, sizeof(tmp));
208e5b75505Sopenharmony_ci		siz = left > EXTRACT_LEN ? EXTRACT_LEN : left;
209e5b75505Sopenharmony_ci		for (i = 0; i < siz; i++)
210e5b75505Sopenharmony_ci			*bytes++ ^= tmp[i];
211e5b75505Sopenharmony_ci		left -= siz;
212e5b75505Sopenharmony_ci	}
213e5b75505Sopenharmony_ci#endif /* CONFIG_FIPS */
214e5b75505Sopenharmony_ci
215e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_EXCESSIVE, "mixed random", buf, len);
216e5b75505Sopenharmony_ci
217e5b75505Sopenharmony_ci	if (entropy < len)
218e5b75505Sopenharmony_ci		entropy = 0;
219e5b75505Sopenharmony_ci	else
220e5b75505Sopenharmony_ci		entropy -= len;
221e5b75505Sopenharmony_ci
222e5b75505Sopenharmony_ci	return ret;
223e5b75505Sopenharmony_ci#endif /* CONFIG_TEST_RANDOM */
224e5b75505Sopenharmony_ci}
225e5b75505Sopenharmony_ci
226e5b75505Sopenharmony_ci
227e5b75505Sopenharmony_ciint random_pool_ready(void)
228e5b75505Sopenharmony_ci{
229e5b75505Sopenharmony_ci#ifdef CONFIG_TEST_RANDOM
230e5b75505Sopenharmony_ci    return 1;
231e5b75505Sopenharmony_ci#else /* CONFIG_TEST_RANDOM */
232e5b75505Sopenharmony_ci#ifdef __linux__
233e5b75505Sopenharmony_ci	int fd;
234e5b75505Sopenharmony_ci	ssize_t res;
235e5b75505Sopenharmony_ci
236e5b75505Sopenharmony_ci	/*
237e5b75505Sopenharmony_ci	 * Make sure that there is reasonable entropy available before allowing
238e5b75505Sopenharmony_ci	 * some key derivation operations to proceed.
239e5b75505Sopenharmony_ci	 */
240e5b75505Sopenharmony_ci
241e5b75505Sopenharmony_ci	if (dummy_key_avail == sizeof(dummy_key))
242e5b75505Sopenharmony_ci		return 1; /* Already initialized - good to continue */
243e5b75505Sopenharmony_ci
244e5b75505Sopenharmony_ci	/*
245e5b75505Sopenharmony_ci	 * Try to fetch some more data from the kernel high quality RNG.
246e5b75505Sopenharmony_ci	 * There may not be enough data available at this point,
247e5b75505Sopenharmony_ci	 * so use non-blocking read to avoid blocking the application
248e5b75505Sopenharmony_ci	 * completely.
249e5b75505Sopenharmony_ci	 */
250e5b75505Sopenharmony_ci
251e5b75505Sopenharmony_ci#ifdef CONFIG_GETRANDOM
252e5b75505Sopenharmony_ci	res = getrandom(dummy_key + dummy_key_avail,
253e5b75505Sopenharmony_ci			sizeof(dummy_key) - dummy_key_avail, GRND_NONBLOCK);
254e5b75505Sopenharmony_ci	if (res < 0) {
255e5b75505Sopenharmony_ci		if (errno == ENOSYS) {
256e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
257e5b75505Sopenharmony_ci				   "random: getrandom() not supported, falling back to /dev/random");
258e5b75505Sopenharmony_ci		} else {
259e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO,
260e5b75505Sopenharmony_ci				   "random: no data from getrandom(): %s",
261e5b75505Sopenharmony_ci				   strerror(errno));
262e5b75505Sopenharmony_ci			res = 0;
263e5b75505Sopenharmony_ci		}
264e5b75505Sopenharmony_ci	}
265e5b75505Sopenharmony_ci#else /* CONFIG_GETRANDOM */
266e5b75505Sopenharmony_ci	res = -1;
267e5b75505Sopenharmony_ci#endif /* CONFIG_GETRANDOM */
268e5b75505Sopenharmony_ci	if (res < 0) {
269e5b75505Sopenharmony_ci		fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
270e5b75505Sopenharmony_ci		if (fd < 0) {
271e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR,
272e5b75505Sopenharmony_ci				   "random: Cannot open /dev/random: %s",
273e5b75505Sopenharmony_ci				   strerror(errno));
274e5b75505Sopenharmony_ci			return -1;
275e5b75505Sopenharmony_ci		}
276e5b75505Sopenharmony_ci
277e5b75505Sopenharmony_ci		res = read(fd, dummy_key + dummy_key_avail,
278e5b75505Sopenharmony_ci			   sizeof(dummy_key) - dummy_key_avail);
279e5b75505Sopenharmony_ci		if (res < 0) {
280e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR,
281e5b75505Sopenharmony_ci				   "random: Cannot read from /dev/random: %s",
282e5b75505Sopenharmony_ci				   strerror(errno));
283e5b75505Sopenharmony_ci			res = 0;
284e5b75505Sopenharmony_ci		}
285e5b75505Sopenharmony_ci		close(fd);
286e5b75505Sopenharmony_ci	}
287e5b75505Sopenharmony_ci
288e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "random: Got %u/%u random bytes", (unsigned) res,
289e5b75505Sopenharmony_ci		   (unsigned) (sizeof(dummy_key) - dummy_key_avail));
290e5b75505Sopenharmony_ci	dummy_key_avail += res;
291e5b75505Sopenharmony_ci
292e5b75505Sopenharmony_ci	if (dummy_key_avail == sizeof(dummy_key)) {
293e5b75505Sopenharmony_ci		if (own_pool_ready < MIN_READY_MARK)
294e5b75505Sopenharmony_ci			own_pool_ready = MIN_READY_MARK;
295e5b75505Sopenharmony_ci		random_write_entropy();
296e5b75505Sopenharmony_ci		return 1;
297e5b75505Sopenharmony_ci	}
298e5b75505Sopenharmony_ci
299e5b75505Sopenharmony_ci	wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
300e5b75505Sopenharmony_ci		   "random data available",
301e5b75505Sopenharmony_ci		   (unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
302e5b75505Sopenharmony_ci
303e5b75505Sopenharmony_ci	if (own_pool_ready >= MIN_READY_MARK ||
304e5b75505Sopenharmony_ci	    total_collected + 10 * own_pool_ready > MIN_COLLECT_ENTROPY) {
305e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "random: Allow operation to proceed "
306e5b75505Sopenharmony_ci			   "based on internal entropy");
307e5b75505Sopenharmony_ci		return 1;
308e5b75505Sopenharmony_ci	}
309e5b75505Sopenharmony_ci
310e5b75505Sopenharmony_ci	wpa_printf(MSG_INFO, "random: Not enough entropy pool available for "
311e5b75505Sopenharmony_ci		   "secure operations");
312e5b75505Sopenharmony_ci	return 0;
313e5b75505Sopenharmony_ci#else /* __linux__ */
314e5b75505Sopenharmony_ci	/* TODO: could do similar checks on non-Linux platforms */
315e5b75505Sopenharmony_ci	return 1;
316e5b75505Sopenharmony_ci#endif /* __linux__ */
317e5b75505Sopenharmony_ci#endif /* CONFIG_TEST_RANDOM */
318e5b75505Sopenharmony_ci}
319e5b75505Sopenharmony_ci
320e5b75505Sopenharmony_ci
321e5b75505Sopenharmony_civoid random_mark_pool_ready(void)
322e5b75505Sopenharmony_ci{
323e5b75505Sopenharmony_ci	own_pool_ready++;
324e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be "
325e5b75505Sopenharmony_ci		   "ready (count=%u/%u)", own_pool_ready, MIN_READY_MARK);
326e5b75505Sopenharmony_ci	random_write_entropy();
327e5b75505Sopenharmony_ci}
328e5b75505Sopenharmony_ci
329e5b75505Sopenharmony_ci
330e5b75505Sopenharmony_ci#ifdef __linux__
331e5b75505Sopenharmony_ci
332e5b75505Sopenharmony_cistatic void random_close_fd(void)
333e5b75505Sopenharmony_ci{
334e5b75505Sopenharmony_ci	if (random_fd >= 0) {
335e5b75505Sopenharmony_ci		eloop_unregister_read_sock(random_fd);
336e5b75505Sopenharmony_ci		close(random_fd);
337e5b75505Sopenharmony_ci		random_fd = -1;
338e5b75505Sopenharmony_ci	}
339e5b75505Sopenharmony_ci}
340e5b75505Sopenharmony_ci
341e5b75505Sopenharmony_ci
342e5b75505Sopenharmony_cistatic void random_read_fd(int sock, void *eloop_ctx, void *sock_ctx)
343e5b75505Sopenharmony_ci{
344e5b75505Sopenharmony_ci	ssize_t res;
345e5b75505Sopenharmony_ci
346e5b75505Sopenharmony_ci	if (dummy_key_avail == sizeof(dummy_key)) {
347e5b75505Sopenharmony_ci		random_close_fd();
348e5b75505Sopenharmony_ci		return;
349e5b75505Sopenharmony_ci	}
350e5b75505Sopenharmony_ci
351e5b75505Sopenharmony_ci	res = read(sock, dummy_key + dummy_key_avail,
352e5b75505Sopenharmony_ci		   sizeof(dummy_key) - dummy_key_avail);
353e5b75505Sopenharmony_ci	if (res < 0) {
354e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
355e5b75505Sopenharmony_ci			   "%s", strerror(errno));
356e5b75505Sopenharmony_ci		return;
357e5b75505Sopenharmony_ci	}
358e5b75505Sopenharmony_ci
359e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from /dev/random",
360e5b75505Sopenharmony_ci		   (unsigned) res,
361e5b75505Sopenharmony_ci		   (unsigned) (sizeof(dummy_key) - dummy_key_avail));
362e5b75505Sopenharmony_ci	dummy_key_avail += res;
363e5b75505Sopenharmony_ci
364e5b75505Sopenharmony_ci	if (dummy_key_avail == sizeof(dummy_key)) {
365e5b75505Sopenharmony_ci		random_close_fd();
366e5b75505Sopenharmony_ci		if (own_pool_ready < MIN_READY_MARK)
367e5b75505Sopenharmony_ci			own_pool_ready = MIN_READY_MARK;
368e5b75505Sopenharmony_ci		random_write_entropy();
369e5b75505Sopenharmony_ci	}
370e5b75505Sopenharmony_ci}
371e5b75505Sopenharmony_ci
372e5b75505Sopenharmony_ci#endif /* __linux__ */
373e5b75505Sopenharmony_ci
374e5b75505Sopenharmony_ci
375e5b75505Sopenharmony_cistatic void random_read_entropy(void)
376e5b75505Sopenharmony_ci{
377e5b75505Sopenharmony_ci	char *buf;
378e5b75505Sopenharmony_ci	size_t len;
379e5b75505Sopenharmony_ci
380e5b75505Sopenharmony_ci	if (!random_entropy_file)
381e5b75505Sopenharmony_ci		return;
382e5b75505Sopenharmony_ci
383e5b75505Sopenharmony_ci	buf = os_readfile(random_entropy_file, &len);
384e5b75505Sopenharmony_ci	if (buf == NULL)
385e5b75505Sopenharmony_ci		return; /* entropy file not yet available */
386e5b75505Sopenharmony_ci
387e5b75505Sopenharmony_ci	if (len != 1 + RANDOM_ENTROPY_SIZE) {
388e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "random: Invalid entropy file %s",
389e5b75505Sopenharmony_ci			   random_entropy_file);
390e5b75505Sopenharmony_ci		os_free(buf);
391e5b75505Sopenharmony_ci		return;
392e5b75505Sopenharmony_ci	}
393e5b75505Sopenharmony_ci
394e5b75505Sopenharmony_ci	own_pool_ready = (u8) buf[0];
395e5b75505Sopenharmony_ci	random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE);
396e5b75505Sopenharmony_ci	os_free(buf);
397e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "random: Added entropy from %s "
398e5b75505Sopenharmony_ci		   "(own_pool_ready=%u)",
399e5b75505Sopenharmony_ci		   random_entropy_file, own_pool_ready);
400e5b75505Sopenharmony_ci}
401e5b75505Sopenharmony_ci
402e5b75505Sopenharmony_ci
403e5b75505Sopenharmony_cistatic void random_write_entropy(void)
404e5b75505Sopenharmony_ci{
405e5b75505Sopenharmony_ci	char buf[RANDOM_ENTROPY_SIZE];
406e5b75505Sopenharmony_ci	FILE *f;
407e5b75505Sopenharmony_ci	u8 opr;
408e5b75505Sopenharmony_ci	int fail = 0;
409e5b75505Sopenharmony_ci
410e5b75505Sopenharmony_ci	if (!random_entropy_file)
411e5b75505Sopenharmony_ci		return;
412e5b75505Sopenharmony_ci
413e5b75505Sopenharmony_ci	if (random_get_bytes(buf, RANDOM_ENTROPY_SIZE) < 0)
414e5b75505Sopenharmony_ci		return;
415e5b75505Sopenharmony_ci
416e5b75505Sopenharmony_ci	f = fopen(random_entropy_file, "wb");
417e5b75505Sopenharmony_ci	if (f == NULL) {
418e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "random: Could not open entropy file %s "
419e5b75505Sopenharmony_ci			   "for writing", random_entropy_file);
420e5b75505Sopenharmony_ci		return;
421e5b75505Sopenharmony_ci	}
422e5b75505Sopenharmony_ci
423e5b75505Sopenharmony_ci	opr = own_pool_ready > 0xff ? 0xff : own_pool_ready;
424e5b75505Sopenharmony_ci	if (fwrite(&opr, 1, 1, f) != 1 ||
425e5b75505Sopenharmony_ci	    fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f) != 1)
426e5b75505Sopenharmony_ci		fail = 1;
427e5b75505Sopenharmony_ci	fclose(f);
428e5b75505Sopenharmony_ci	if (fail) {
429e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "random: Could not write entropy data "
430e5b75505Sopenharmony_ci			   "to %s", random_entropy_file);
431e5b75505Sopenharmony_ci		return;
432e5b75505Sopenharmony_ci	}
433e5b75505Sopenharmony_ci
434e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "random: Updated entropy file %s "
435e5b75505Sopenharmony_ci		   "(own_pool_ready=%u)",
436e5b75505Sopenharmony_ci		   random_entropy_file, own_pool_ready);
437e5b75505Sopenharmony_ci}
438e5b75505Sopenharmony_ci
439e5b75505Sopenharmony_ci
440e5b75505Sopenharmony_civoid random_init(const char *entropy_file)
441e5b75505Sopenharmony_ci{
442e5b75505Sopenharmony_ci	os_free(random_entropy_file);
443e5b75505Sopenharmony_ci	if (entropy_file)
444e5b75505Sopenharmony_ci		random_entropy_file = os_strdup(entropy_file);
445e5b75505Sopenharmony_ci	else
446e5b75505Sopenharmony_ci		random_entropy_file = NULL;
447e5b75505Sopenharmony_ci	random_read_entropy();
448e5b75505Sopenharmony_ci
449e5b75505Sopenharmony_ci#ifdef __linux__
450e5b75505Sopenharmony_ci	if (random_fd >= 0)
451e5b75505Sopenharmony_ci		return;
452e5b75505Sopenharmony_ci
453e5b75505Sopenharmony_ci#ifdef CONFIG_GETRANDOM
454e5b75505Sopenharmony_ci	{
455e5b75505Sopenharmony_ci		u8 dummy;
456e5b75505Sopenharmony_ci
457e5b75505Sopenharmony_ci		if (getrandom(&dummy, 0, GRND_NONBLOCK) == 0 ||
458e5b75505Sopenharmony_ci		    errno != ENOSYS) {
459e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
460e5b75505Sopenharmony_ci				   "random: getrandom() support available");
461e5b75505Sopenharmony_ci			return;
462e5b75505Sopenharmony_ci		}
463e5b75505Sopenharmony_ci	}
464e5b75505Sopenharmony_ci#endif /* CONFIG_GETRANDOM */
465e5b75505Sopenharmony_ci
466e5b75505Sopenharmony_ci	random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
467e5b75505Sopenharmony_ci	if (random_fd < 0) {
468e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
469e5b75505Sopenharmony_ci			   strerror(errno));
470e5b75505Sopenharmony_ci		return;
471e5b75505Sopenharmony_ci	}
472e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "random: Trying to read entropy from "
473e5b75505Sopenharmony_ci		   "/dev/random");
474e5b75505Sopenharmony_ci
475e5b75505Sopenharmony_ci	eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL);
476e5b75505Sopenharmony_ci#endif /* __linux__ */
477e5b75505Sopenharmony_ci
478e5b75505Sopenharmony_ci	random_write_entropy();
479e5b75505Sopenharmony_ci}
480e5b75505Sopenharmony_ci
481e5b75505Sopenharmony_ci
482e5b75505Sopenharmony_civoid random_deinit(void)
483e5b75505Sopenharmony_ci{
484e5b75505Sopenharmony_ci#ifdef __linux__
485e5b75505Sopenharmony_ci	random_close_fd();
486e5b75505Sopenharmony_ci#endif /* __linux__ */
487e5b75505Sopenharmony_ci	random_write_entropy();
488e5b75505Sopenharmony_ci	os_free(random_entropy_file);
489e5b75505Sopenharmony_ci	random_entropy_file = NULL;
490e5b75505Sopenharmony_ci}
491