2018-05-02 19:43:17 +00:00
|
|
|
#include "tommath_private.h"
|
2004-10-29 22:07:18 +00:00
|
|
|
#ifdef BN_MP_RAND_C
|
2019-04-07 13:29:11 +00:00
|
|
|
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
|
|
|
/* SPDX-License-Identifier: Unlicense */
|
2003-02-28 16:08:34 +00:00
|
|
|
|
2018-04-14 12:33:36 +00:00
|
|
|
/* First the OS-specific special cases
|
|
|
|
* - *BSD
|
|
|
|
* - Windows
|
|
|
|
*/
|
|
|
|
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
|
2019-05-07 10:26:46 +00:00
|
|
|
# define MP_ARC4RANDOM
|
2018-04-14 12:33:36 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(_WIN32_WCE)
|
|
|
|
#define MP_WIN_CSP
|
|
|
|
|
|
|
|
#ifndef _WIN32_WINNT
|
2018-09-23 19:37:58 +00:00
|
|
|
#define _WIN32_WINNT 0x0400
|
2018-04-14 12:33:36 +00:00
|
|
|
#endif
|
|
|
|
#ifdef _WIN32_WCE
|
2018-09-23 19:37:58 +00:00
|
|
|
#define UNDER_CE
|
|
|
|
#define ARM
|
2018-04-14 12:33:36 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#include <windows.h>
|
|
|
|
#include <wincrypt.h>
|
|
|
|
|
|
|
|
static HCRYPTPROV hProv = 0;
|
|
|
|
|
|
|
|
static void s_cleanup_win_csp(void)
|
|
|
|
{
|
|
|
|
CryptReleaseContext(hProv, 0);
|
|
|
|
hProv = 0;
|
|
|
|
}
|
|
|
|
|
2019-05-07 10:26:46 +00:00
|
|
|
static int s_read_win_csp(void *p, size_t n)
|
2018-04-14 12:33:36 +00:00
|
|
|
{
|
|
|
|
if (hProv == 0) {
|
|
|
|
if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
|
|
|
|
(CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) &&
|
2018-09-23 19:37:58 +00:00
|
|
|
!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
|
2018-04-14 12:33:36 +00:00
|
|
|
CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) {
|
|
|
|
hProv = 0;
|
2019-05-07 10:26:46 +00:00
|
|
|
return MP_ERR;
|
2018-04-14 12:33:36 +00:00
|
|
|
}
|
|
|
|
atexit(s_cleanup_win_csp);
|
|
|
|
}
|
2019-05-07 10:26:46 +00:00
|
|
|
return CryptGenRandom(hProv, (DWORD)n, (BYTE *)p) == TRUE ? MP_OKAY : MP_ERR;
|
2018-04-14 12:33:36 +00:00
|
|
|
}
|
|
|
|
#endif /* WIN32 */
|
|
|
|
|
|
|
|
#if !defined(MP_WIN_CSP) && defined(__linux__) && defined(__GLIBC_PREREQ)
|
|
|
|
#if __GLIBC_PREREQ(2, 25)
|
|
|
|
#define MP_GETRANDOM
|
|
|
|
#include <sys/random.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
2019-05-07 10:26:46 +00:00
|
|
|
static int s_read_getrandom(void *p, size_t n)
|
2018-04-14 12:33:36 +00:00
|
|
|
{
|
2019-05-07 10:26:46 +00:00
|
|
|
char *q = (char *)p;
|
|
|
|
while (n > 0) {
|
|
|
|
ssize_t ret = getrandom(q, n, 0);
|
|
|
|
if (ret < 0) {
|
|
|
|
if (errno == EINTR) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
return MP_ERR;
|
|
|
|
}
|
|
|
|
q += ret;
|
|
|
|
n -= (size_t)ret;
|
|
|
|
}
|
|
|
|
return MP_OKAY;
|
2018-04-14 12:33:36 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* We assume all platforms besides windows provide "/dev/urandom".
|
|
|
|
* In case yours doesn't, define MP_NO_DEV_URANDOM at compile-time.
|
|
|
|
*/
|
|
|
|
#if !defined(MP_WIN_CSP) && !defined(MP_NO_DEV_URANDOM)
|
|
|
|
#ifndef MP_DEV_URANDOM
|
|
|
|
#define MP_DEV_URANDOM "/dev/urandom"
|
|
|
|
#endif
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2019-05-07 10:26:46 +00:00
|
|
|
static int s_read_dev_urandom(void *p, size_t n)
|
2018-04-14 12:33:36 +00:00
|
|
|
{
|
|
|
|
int fd;
|
2019-05-07 10:26:46 +00:00
|
|
|
char *q = (char *)p;
|
|
|
|
|
2018-04-14 12:33:36 +00:00
|
|
|
do {
|
|
|
|
fd = open(MP_DEV_URANDOM, O_RDONLY);
|
2018-09-23 19:37:58 +00:00
|
|
|
} while ((fd == -1) && (errno == EINTR));
|
2019-05-07 10:26:46 +00:00
|
|
|
if (fd == -1) return MP_ERR;
|
|
|
|
|
|
|
|
while (n > 0) {
|
|
|
|
ssize_t ret = read(fd, p, n);
|
|
|
|
if (ret < 0) {
|
|
|
|
if (errno == EINTR) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
return MP_ERR;
|
|
|
|
}
|
|
|
|
q += ret;
|
|
|
|
n -= (size_t)ret;
|
|
|
|
}
|
|
|
|
|
2018-04-14 12:33:36 +00:00
|
|
|
close(fd);
|
|
|
|
return MP_OKAY;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(MP_PRNG_ENABLE_LTM_RNG)
|
|
|
|
unsigned long (*ltm_rng)(unsigned char *out, unsigned long outlen, void (*callback)(void));
|
|
|
|
void (*ltm_rng_callback)(void);
|
|
|
|
|
2019-05-07 10:26:46 +00:00
|
|
|
static int s_read_ltm_rng(void *p, size_t n)
|
2018-04-14 12:33:36 +00:00
|
|
|
{
|
|
|
|
unsigned long ret;
|
2019-05-07 10:26:46 +00:00
|
|
|
if (ltm_rng == NULL) return MP_ERR;
|
|
|
|
ret = ltm_rng(p, n, ltm_rng_callback);
|
|
|
|
if (ret != n) return MP_ERR;
|
2018-04-14 12:33:36 +00:00
|
|
|
return MP_OKAY;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-05-07 10:26:46 +00:00
|
|
|
static int s_mp_rand_source_platform(void *p, size_t n)
|
2018-04-14 12:33:36 +00:00
|
|
|
{
|
2019-05-07 10:26:46 +00:00
|
|
|
int ret = MP_ERR;
|
2018-04-14 12:33:36 +00:00
|
|
|
|
|
|
|
#if defined(MP_ARC4RANDOM)
|
2019-05-07 10:26:46 +00:00
|
|
|
arc4random_buf(p, n);
|
|
|
|
return MP_OKAY;
|
2018-04-14 12:33:36 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(MP_WIN_CSP)
|
2019-05-07 10:26:46 +00:00
|
|
|
ret = s_read_win_csp(p, n);
|
2018-04-14 12:33:36 +00:00
|
|
|
if (ret == MP_OKAY) return ret;
|
|
|
|
#else
|
|
|
|
|
|
|
|
#if defined(MP_GETRANDOM)
|
2019-05-07 10:26:46 +00:00
|
|
|
ret = s_read_getrandom(p, n);
|
2018-04-14 12:33:36 +00:00
|
|
|
if (ret == MP_OKAY) return ret;
|
|
|
|
#endif
|
|
|
|
#if defined(MP_DEV_URANDOM)
|
2019-05-07 10:26:46 +00:00
|
|
|
ret = s_read_dev_urandom(p, n);
|
2018-04-14 12:33:36 +00:00
|
|
|
if (ret == MP_OKAY) return ret;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* MP_WIN_CSP */
|
|
|
|
|
|
|
|
#if defined(MP_PRNG_ENABLE_LTM_RNG)
|
2019-05-07 10:26:46 +00:00
|
|
|
ret = s_read_ltm_rng(p, n);
|
2018-04-14 12:33:36 +00:00
|
|
|
if (ret == MP_OKAY) return ret;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-05-07 10:26:46 +00:00
|
|
|
static int (*s_rand_source)(void *, size_t) = s_mp_rand_source_platform;
|
|
|
|
|
|
|
|
void mp_rand_source(int (*get)(void *out, size_t size))
|
|
|
|
{
|
|
|
|
s_rand_source = get;
|
|
|
|
}
|
|
|
|
|
2018-04-14 12:33:36 +00:00
|
|
|
/* makes a pseudo-random int of a given size */
|
2019-01-13 19:21:36 +00:00
|
|
|
int mp_rand_digit(mp_digit *r)
|
2018-04-14 12:33:36 +00:00
|
|
|
{
|
2019-05-07 10:26:46 +00:00
|
|
|
int ret = s_rand_source(r, sizeof(mp_digit));
|
2018-04-14 12:33:36 +00:00
|
|
|
*r &= MP_MASK;
|
|
|
|
return ret;
|
2016-04-09 23:01:29 +00:00
|
|
|
}
|
|
|
|
|
2017-08-30 17:07:12 +00:00
|
|
|
int mp_rand(mp_int *a, int digits)
|
2003-02-28 16:08:34 +00:00
|
|
|
{
|
2019-05-07 10:26:46 +00:00
|
|
|
int ret, i;
|
2003-02-28 16:08:34 +00:00
|
|
|
|
2017-08-30 18:23:46 +00:00
|
|
|
mp_zero(a);
|
2019-05-07 10:26:46 +00:00
|
|
|
|
2017-08-30 18:23:46 +00:00
|
|
|
if (digits <= 0) {
|
|
|
|
return MP_OKAY;
|
|
|
|
}
|
2003-02-28 16:08:34 +00:00
|
|
|
|
2019-05-07 10:26:46 +00:00
|
|
|
if ((ret = mp_grow(a, digits)) != MP_OKAY) {
|
|
|
|
return ret;
|
|
|
|
}
|
2003-02-28 16:08:34 +00:00
|
|
|
|
2019-05-07 10:26:46 +00:00
|
|
|
if ((ret = s_rand_source(a->dp, (size_t)digits * sizeof(mp_digit))) != MP_OKAY) {
|
|
|
|
return ret;
|
2017-08-30 18:23:46 +00:00
|
|
|
}
|
2003-02-28 16:09:08 +00:00
|
|
|
|
2019-05-07 10:26:46 +00:00
|
|
|
/* TODO: We ensure that the highest digit is nonzero. Should this be removed? */
|
|
|
|
while ((a->dp[digits - 1] & MP_MASK) == 0) {
|
|
|
|
if ((ret = s_rand_source(a->dp + digits - 1, sizeof(mp_digit))) != MP_OKAY) {
|
|
|
|
return ret;
|
2017-08-30 18:23:46 +00:00
|
|
|
}
|
2019-05-07 10:26:46 +00:00
|
|
|
}
|
2017-08-30 18:23:46 +00:00
|
|
|
|
2019-05-07 10:26:46 +00:00
|
|
|
a->used = digits;
|
|
|
|
for (i = 0; i < digits; ++i) {
|
|
|
|
a->dp[i] &= MP_MASK;
|
2017-08-30 18:23:46 +00:00
|
|
|
}
|
2003-02-28 16:08:34 +00:00
|
|
|
|
2017-08-30 18:23:46 +00:00
|
|
|
return MP_OKAY;
|
2003-02-28 16:08:34 +00:00
|
|
|
}
|
2004-10-29 22:07:18 +00:00
|
|
|
#endif
|