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 stub_key[20]; 54e5b75505Sopenharmony_ci#ifdef __linux__ 55e5b75505Sopenharmony_cistatic size_t stub_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(stub_key, sizeof(stub_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(stub_key, sizeof(stub_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 (stub_key_avail == sizeof(stub_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(stub_key + stub_key_avail, 253e5b75505Sopenharmony_ci sizeof(stub_key) - stub_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, stub_key + stub_key_avail, 278e5b75505Sopenharmony_ci sizeof(stub_key) - stub_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(stub_key) - stub_key_avail)); 290e5b75505Sopenharmony_ci stub_key_avail += res; 291e5b75505Sopenharmony_ci 292e5b75505Sopenharmony_ci if (stub_key_avail == sizeof(stub_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) stub_key_avail, (unsigned) sizeof(stub_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 (stub_key_avail == sizeof(stub_key)) { 347e5b75505Sopenharmony_ci random_close_fd(); 348e5b75505Sopenharmony_ci return; 349e5b75505Sopenharmony_ci } 350e5b75505Sopenharmony_ci 351e5b75505Sopenharmony_ci res = read(sock, stub_key + stub_key_avail, 352e5b75505Sopenharmony_ci sizeof(stub_key) - stub_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(stub_key) - stub_key_avail)); 362e5b75505Sopenharmony_ci stub_key_avail += res; 363e5b75505Sopenharmony_ci 364e5b75505Sopenharmony_ci if (stub_key_avail == sizeof(stub_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 stub; 456e5b75505Sopenharmony_ci 457e5b75505Sopenharmony_ci if (getrandom(&stub, 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