diff options
Diffstat (limited to 'libtommath/bn_mp_rand.c')
-rw-r--r-- | libtommath/bn_mp_rand.c | 246 |
1 files changed, 194 insertions, 52 deletions
diff --git a/libtommath/bn_mp_rand.c b/libtommath/bn_mp_rand.c index 93e255a..06a6f93 100644 --- a/libtommath/bn_mp_rand.c +++ b/libtommath/bn_mp_rand.c @@ -1,4 +1,4 @@ -#include <tommath_private.h> +#include "tommath_private.h" #ifdef BN_MP_RAND_C /* LibTomMath, multiple-precision integer library -- Tom St Denis * @@ -9,72 +9,214 @@ * Michael Fromberger but has been written from scratch with * additional optimizations in place. * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tstdenis82@gmail.com, http://libtom.org + * SPDX-License-Identifier: Unlicense + */ + +/* First the OS-specific special cases + * - *BSD + * - Windows */ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +#define MP_ARC4RANDOM +#define MP_GEN_RANDOM_MAX 0xffffffffu +#define MP_GEN_RANDOM_SHIFT 32 -#if MP_GEN_RANDOM_MAX == 0xffffffff - #define MP_GEN_RANDOM_SHIFT 32 -#elif MP_GEN_RANDOM_MAX == 32767 - /* SHRT_MAX */ - #define MP_GEN_RANDOM_SHIFT 15 -#elif MP_GEN_RANDOM_MAX == 2147483647 - /* INT_MAX */ - #define MP_GEN_RANDOM_SHIFT 31 -#elif !defined(MP_GEN_RANDOM_SHIFT) -#error Thou shalt define their own valid MP_GEN_RANDOM_SHIFT +static int s_read_arc4random(mp_digit *p) +{ + mp_digit d = 0, msk = 0; + do { + d <<= MP_GEN_RANDOM_SHIFT; + d |= ((mp_digit) arc4random()); + msk <<= MP_GEN_RANDOM_SHIFT; + msk |= (MP_MASK & MP_GEN_RANDOM_MAX); + } while ((MP_MASK & msk) != MP_MASK); + *p = d; + return MP_OKAY; +} #endif -/* makes a pseudo-random int of a given size */ -static mp_digit s_gen_random(void) +#if defined(_WIN32) || defined(_WIN32_WCE) +#define MP_WIN_CSP + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#endif +#ifdef _WIN32_WCE +#define UNDER_CE +#define ARM +#endif + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <wincrypt.h> + +static HCRYPTPROV hProv = 0; + +static void s_cleanup_win_csp(void) { - mp_digit d = 0, msk = 0; - do { - d <<= MP_GEN_RANDOM_SHIFT; - d |= ((mp_digit) MP_GEN_RANDOM()); - msk <<= MP_GEN_RANDOM_SHIFT; - msk |= (MP_MASK & MP_GEN_RANDOM_MAX); - } while ((MP_MASK & msk) != MP_MASK); - d &= MP_MASK; - return d; + CryptReleaseContext(hProv, 0); + hProv = 0; } -int -mp_rand (mp_int * a, int digits) +static int s_read_win_csp(mp_digit *p) { - int res; - mp_digit d; + int ret = -1; + if (hProv == 0) { + if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, + (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) && + !CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) { + hProv = 0; + return ret; + } + atexit(s_cleanup_win_csp); + } + if (CryptGenRandom(hProv, sizeof(*p), (void *)p) == TRUE) { + ret = MP_OKAY; + } + return ret; +} +#endif /* WIN32 */ - mp_zero (a); - if (digits <= 0) { - return MP_OKAY; - } +#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> - /* first place a random non-zero digit */ - do { - d = s_gen_random(); - } while (d == 0); +static int s_read_getrandom(mp_digit *p) +{ + int ret; + do { + ret = getrandom(p, sizeof(*p), 0); + } while ((ret == -1) && (errno == EINTR)); + if (ret == sizeof(*p)) return MP_OKAY; + return -1; +} +#endif +#endif - if ((res = mp_add_d (a, d, a)) != MP_OKAY) { - return res; - } +/* 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> - while (--digits > 0) { - if ((res = mp_lshd (a, 1)) != MP_OKAY) { - return res; - } +static int s_read_dev_urandom(mp_digit *p) +{ + ssize_t r; + int fd; + do { + fd = open(MP_DEV_URANDOM, O_RDONLY); + } while ((fd == -1) && (errno == EINTR)); + if (fd == -1) return -1; + do { + r = read(fd, p, sizeof(*p)); + } while ((r == -1) && (errno == EINTR)); + close(fd); + if (r != sizeof(*p)) return -1; + return MP_OKAY; +} +#endif - if ((res = mp_add_d (a, s_gen_random(), a)) != MP_OKAY) { +#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); + +static int s_read_ltm_rng(mp_digit *p) +{ + unsigned long ret; + if (ltm_rng == NULL) return -1; + ret = ltm_rng((void *)p, sizeof(*p), ltm_rng_callback); + if (ret != sizeof(*p)) return -1; + return MP_OKAY; +} +#endif + +static int s_rand_digit(mp_digit *p) +{ + int ret = -1; + +#if defined(MP_ARC4RANDOM) + ret = s_read_arc4random(p); + if (ret == MP_OKAY) return ret; +#endif + +#if defined(MP_WIN_CSP) + ret = s_read_win_csp(p); + if (ret == MP_OKAY) return ret; +#else + +#if defined(MP_GETRANDOM) + ret = s_read_getrandom(p); + if (ret == MP_OKAY) return ret; +#endif +#if defined(MP_DEV_URANDOM) + ret = s_read_dev_urandom(p); + if (ret == MP_OKAY) return ret; +#endif + +#endif /* MP_WIN_CSP */ + +#if defined(MP_PRNG_ENABLE_LTM_RNG) + ret = s_read_ltm_rng(p); + if (ret == MP_OKAY) return ret; +#endif + + return ret; +} + +/* makes a pseudo-random int of a given size */ +int mp_rand_digit(mp_digit *r) +{ + int ret = s_rand_digit(r); + *r &= MP_MASK; + return ret; +} + +int mp_rand(mp_int *a, int digits) +{ + int res; + mp_digit d; + + mp_zero(a); + if (digits <= 0) { + return MP_OKAY; + } + + /* first place a random non-zero digit */ + do { + if (mp_rand_digit(&d) != MP_OKAY) { + return MP_VAL; + } + } while (d == 0u); + + if ((res = mp_add_d(a, d, a)) != MP_OKAY) { return res; - } - } + } + + while (--digits > 0) { + if ((res = mp_lshd(a, 1)) != MP_OKAY) { + return res; + } + + if (mp_rand_digit(&d) != MP_OKAY) { + return MP_VAL; + } + if ((res = mp_add_d(a, d, a)) != MP_OKAY) { + return res; + } + } - return MP_OKAY; + return MP_OKAY; } #endif -/* ref: $Format:%D$ */ -/* git commit: $Format:%H$ */ -/* commit time: $Format:%ai$ */ +/* ref: HEAD -> master, tag: v1.1.0 */ +/* git commit: 08549ad6bc8b0cede0b357a9c341c5c6473a9c55 */ +/* commit time: 2019-01-28 20:32:32 +0100 */ |