153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
653a5a1b3Sopenharmony_ci
753a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
853a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as
953a5a1b3Sopenharmony_ci  published by the Free Software Foundation; either version 2.1 of the
1053a5a1b3Sopenharmony_ci  License, or (at your option) any later version.
1153a5a1b3Sopenharmony_ci
1253a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1353a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1453a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1553a5a1b3Sopenharmony_ci  Lesser General Public License for more details.
1653a5a1b3Sopenharmony_ci
1753a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public
1853a5a1b3Sopenharmony_ci  License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1953a5a1b3Sopenharmony_ci***/
2053a5a1b3Sopenharmony_ci
2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2253a5a1b3Sopenharmony_ci#include <config.h>
2353a5a1b3Sopenharmony_ci#endif
2453a5a1b3Sopenharmony_ci
2553a5a1b3Sopenharmony_ci#include <fcntl.h>
2653a5a1b3Sopenharmony_ci#include <unistd.h>
2753a5a1b3Sopenharmony_ci#include <errno.h>
2853a5a1b3Sopenharmony_ci#include <stdlib.h>
2953a5a1b3Sopenharmony_ci#include <time.h>
3053a5a1b3Sopenharmony_ci
3153a5a1b3Sopenharmony_ci#ifdef HAVE_WINDOWS_H
3253a5a1b3Sopenharmony_ci#include <windows.h>
3353a5a1b3Sopenharmony_ci#include <wincrypt.h>
3453a5a1b3Sopenharmony_ci#endif
3553a5a1b3Sopenharmony_ci
3653a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
3753a5a1b3Sopenharmony_ci#include <pulsecore/log.h>
3853a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
3953a5a1b3Sopenharmony_ci
4053a5a1b3Sopenharmony_ci#include "random.h"
4153a5a1b3Sopenharmony_ci
4253a5a1b3Sopenharmony_cistatic bool has_whined = false;
4353a5a1b3Sopenharmony_ci
4453a5a1b3Sopenharmony_cistatic const char * const devices[] = { "/dev/urandom", "/dev/random", NULL };
4553a5a1b3Sopenharmony_ci
4653a5a1b3Sopenharmony_cistatic int random_proper(void *ret_data, size_t length) {
4753a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32
4853a5a1b3Sopenharmony_ci    int ret = -1;
4953a5a1b3Sopenharmony_ci
5053a5a1b3Sopenharmony_ci    HCRYPTPROV hCryptProv = 0;
5153a5a1b3Sopenharmony_ci
5253a5a1b3Sopenharmony_ci    pa_assert(ret_data);
5353a5a1b3Sopenharmony_ci    pa_assert(length > 0);
5453a5a1b3Sopenharmony_ci
5553a5a1b3Sopenharmony_ci    if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
5653a5a1b3Sopenharmony_ci        if (CryptGenRandom(hCryptProv, length, ret_data))
5753a5a1b3Sopenharmony_ci            ret = 0;
5853a5a1b3Sopenharmony_ci        CryptReleaseContext(hCryptProv, 0);
5953a5a1b3Sopenharmony_ci    }
6053a5a1b3Sopenharmony_ci
6153a5a1b3Sopenharmony_ci    return ret;
6253a5a1b3Sopenharmony_ci
6353a5a1b3Sopenharmony_ci#else /* OS_IS_WIN32 */
6453a5a1b3Sopenharmony_ci
6553a5a1b3Sopenharmony_ci    int fd, ret = -1;
6653a5a1b3Sopenharmony_ci    ssize_t r = 0;
6753a5a1b3Sopenharmony_ci    const char *const * device;
6853a5a1b3Sopenharmony_ci
6953a5a1b3Sopenharmony_ci    pa_assert(ret_data);
7053a5a1b3Sopenharmony_ci    pa_assert(length > 0);
7153a5a1b3Sopenharmony_ci
7253a5a1b3Sopenharmony_ci    device = devices;
7353a5a1b3Sopenharmony_ci
7453a5a1b3Sopenharmony_ci    while (*device) {
7553a5a1b3Sopenharmony_ci        ret = 0;
7653a5a1b3Sopenharmony_ci
7753a5a1b3Sopenharmony_ci        if ((fd = pa_open_cloexec(*device, O_RDONLY, 0)) >= 0) {
7853a5a1b3Sopenharmony_ci
7953a5a1b3Sopenharmony_ci            if ((r = pa_loop_read(fd, ret_data, length, NULL)) < 0 || (size_t) r != length)
8053a5a1b3Sopenharmony_ci                ret = -1;
8153a5a1b3Sopenharmony_ci
8253a5a1b3Sopenharmony_ci            pa_close(fd);
8353a5a1b3Sopenharmony_ci        } else
8453a5a1b3Sopenharmony_ci            ret = -1;
8553a5a1b3Sopenharmony_ci
8653a5a1b3Sopenharmony_ci        if (ret == 0)
8753a5a1b3Sopenharmony_ci            break;
8853a5a1b3Sopenharmony_ci
8953a5a1b3Sopenharmony_ci        device++;
9053a5a1b3Sopenharmony_ci    }
9153a5a1b3Sopenharmony_ci
9253a5a1b3Sopenharmony_ci    return ret;
9353a5a1b3Sopenharmony_ci#endif /* OS_IS_WIN32 */
9453a5a1b3Sopenharmony_ci}
9553a5a1b3Sopenharmony_ci
9653a5a1b3Sopenharmony_civoid pa_random_seed(void) {
9753a5a1b3Sopenharmony_ci    unsigned int seed;
9853a5a1b3Sopenharmony_ci
9953a5a1b3Sopenharmony_ci    if (random_proper(&seed, sizeof(unsigned int)) < 0) {
10053a5a1b3Sopenharmony_ci
10153a5a1b3Sopenharmony_ci        if (!has_whined) {
10253a5a1b3Sopenharmony_ci            pa_log_warn("Failed to get proper entropy. Falling back to seeding with current time.");
10353a5a1b3Sopenharmony_ci            has_whined = true;
10453a5a1b3Sopenharmony_ci        }
10553a5a1b3Sopenharmony_ci
10653a5a1b3Sopenharmony_ci        seed = (unsigned int) time(NULL);
10753a5a1b3Sopenharmony_ci    }
10853a5a1b3Sopenharmony_ci
10953a5a1b3Sopenharmony_ci    srand(seed);
11053a5a1b3Sopenharmony_ci}
11153a5a1b3Sopenharmony_ci
11253a5a1b3Sopenharmony_civoid pa_random(void *ret_data, size_t length) {
11353a5a1b3Sopenharmony_ci    uint8_t *p;
11453a5a1b3Sopenharmony_ci    size_t l;
11553a5a1b3Sopenharmony_ci
11653a5a1b3Sopenharmony_ci    pa_assert(ret_data);
11753a5a1b3Sopenharmony_ci    pa_assert(length > 0);
11853a5a1b3Sopenharmony_ci
11953a5a1b3Sopenharmony_ci    if (random_proper(ret_data, length) >= 0)
12053a5a1b3Sopenharmony_ci        return;
12153a5a1b3Sopenharmony_ci
12253a5a1b3Sopenharmony_ci    if (!has_whined) {
12353a5a1b3Sopenharmony_ci        pa_log_warn("Failed to get proper entropy. Falling back to unsecure pseudo RNG.");
12453a5a1b3Sopenharmony_ci        has_whined = true;
12553a5a1b3Sopenharmony_ci    }
12653a5a1b3Sopenharmony_ci
12753a5a1b3Sopenharmony_ci    for (p = ret_data, l = length; l > 0; p++, l--)
12853a5a1b3Sopenharmony_ci        *p = (uint8_t) rand();
12953a5a1b3Sopenharmony_ci}
130