| 
									
										
										
										
											2018-05-02 21:43:17 +02:00
										 |  |  | #include "tommath_private.h"
 | 
					
						
							| 
									
										
										
										
											2004-10-29 22:07:18 +00:00
										 |  |  | #ifdef BN_MP_RAND_C
 | 
					
						
							| 
									
										
										
										
											2003-02-28 16:08:34 +00:00
										 |  |  | /* LibTomMath, multiple-precision integer library -- Tom St Denis
 | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2003-08-05 01:24:44 +00:00
										 |  |  |  * LibTomMath is a library that provides multiple-precision | 
					
						
							| 
									
										
										
										
											2003-02-28 16:08:34 +00:00
										 |  |  |  * integer arithmetic as well as number theoretic functionality. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2003-08-05 01:24:44 +00:00
										 |  |  |  * The library was designed directly after the MPI library by | 
					
						
							| 
									
										
										
										
											2003-02-28 16:08:34 +00:00
										 |  |  |  * Michael Fromberger but has been written from scratch with | 
					
						
							|  |  |  |  * additional optimizations in place. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-12-29 17:56:20 +01:00
										 |  |  |  * SPDX-License-Identifier: Unlicense | 
					
						
							| 
									
										
										
										
											2003-02-28 16:08:34 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  | /* 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
 | 
					
						
							| 
									
										
										
										
											2016-04-10 13:55:42 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  | static int s_read_arc4random(mp_digit *p) | 
					
						
							| 
									
										
										
										
											2016-04-10 01:01:29 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-08-30 20:23:46 +02:00
										 |  |  |    mp_digit d = 0, msk = 0; | 
					
						
							|  |  |  |    do { | 
					
						
							|  |  |  |       d <<= MP_GEN_RANDOM_SHIFT; | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  |       d |= ((mp_digit) arc4random()); | 
					
						
							| 
									
										
										
										
											2017-08-30 20:23:46 +02:00
										 |  |  |       msk <<= MP_GEN_RANDOM_SHIFT; | 
					
						
							|  |  |  |       msk |= (MP_MASK & MP_GEN_RANDOM_MAX); | 
					
						
							|  |  |  |    } while ((MP_MASK & msk) != MP_MASK); | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  |    *p = d; | 
					
						
							|  |  |  |    return MP_OKAY; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(_WIN32) || defined(_WIN32_WCE)
 | 
					
						
							|  |  |  | #define MP_WIN_CSP
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef _WIN32_WINNT
 | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  | #define _WIN32_WINNT 0x0400
 | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | #ifdef _WIN32_WCE
 | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  | #define UNDER_CE
 | 
					
						
							|  |  |  | #define ARM
 | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02: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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  | static int s_read_win_csp(mp_digit *p) | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  | { | 
					
						
							|  |  |  |    int ret = -1; | 
					
						
							|  |  |  |    if (hProv == 0) { | 
					
						
							|  |  |  |       if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, | 
					
						
							|  |  |  |                                (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) && | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  |           !CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  |                                CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) { | 
					
						
							|  |  |  |          hProv = 0; | 
					
						
							|  |  |  |          return ret; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       atexit(s_cleanup_win_csp); | 
					
						
							|  |  |  |    } | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  |    if (CryptGenRandom(hProv, sizeof(*p), (void *)p) == TRUE) { | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  |       ret = MP_OKAY; | 
					
						
							|  |  |  |    } | 
					
						
							|  |  |  |    return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #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>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  | static int s_read_getrandom(mp_digit *p) | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  | { | 
					
						
							|  |  |  |    int ret; | 
					
						
							|  |  |  |    do { | 
					
						
							|  |  |  |       ret = getrandom(p, sizeof(*p), 0); | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  |    } while ((ret == -1) && (errno == EINTR)); | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  |    if (ret == sizeof(*p)) return MP_OKAY; | 
					
						
							|  |  |  |    return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #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>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  | static int s_read_dev_urandom(mp_digit *p) | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  | { | 
					
						
							|  |  |  |    ssize_t r; | 
					
						
							|  |  |  |    int fd; | 
					
						
							|  |  |  |    do { | 
					
						
							|  |  |  |       fd = open(MP_DEV_URANDOM, O_RDONLY); | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  |    } while ((fd == -1) && (errno == EINTR)); | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  |    if (fd == -1) return -1; | 
					
						
							|  |  |  |    do { | 
					
						
							|  |  |  |       r = read(fd, p, sizeof(*p)); | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  |    } while ((r == -1) && (errno == EINTR)); | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  |    close(fd); | 
					
						
							|  |  |  |    if (r != sizeof(*p)) return -1; | 
					
						
							|  |  |  |    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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  | static int s_read_ltm_rng(mp_digit *p) | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  | { | 
					
						
							|  |  |  |    unsigned long ret; | 
					
						
							|  |  |  |    if (ltm_rng == NULL) return -1; | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  |    ret = ltm_rng((void *)p, sizeof(*p), ltm_rng_callback); | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  |    if (ret != sizeof(*p)) return -1; | 
					
						
							|  |  |  |    return MP_OKAY; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-23 21:37:58 +02:00
										 |  |  | static int s_rand_digit(mp_digit *p) | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  | { | 
					
						
							|  |  |  |    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 */ | 
					
						
							|  |  |  | static int s_gen_random(mp_digit *r) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |    int ret = s_rand_digit(r); | 
					
						
							|  |  |  |    *r &= MP_MASK; | 
					
						
							|  |  |  |    return ret; | 
					
						
							| 
									
										
										
										
											2016-04-10 01:01:29 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 19:07:12 +02:00
										 |  |  | int mp_rand(mp_int *a, int digits) | 
					
						
							| 
									
										
										
										
											2003-02-28 16:08:34 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-08-30 20:23:46 +02:00
										 |  |  |    int     res; | 
					
						
							|  |  |  |    mp_digit d; | 
					
						
							| 
									
										
										
										
											2003-02-28 16:08:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 20:23:46 +02:00
										 |  |  |    mp_zero(a); | 
					
						
							|  |  |  |    if (digits <= 0) { | 
					
						
							|  |  |  |       return MP_OKAY; | 
					
						
							|  |  |  |    } | 
					
						
							| 
									
										
										
										
											2003-02-28 16:08:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 20:23:46 +02:00
										 |  |  |    /* first place a random non-zero digit */ | 
					
						
							|  |  |  |    do { | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  |       if (s_gen_random(&d) != MP_OKAY) { | 
					
						
							|  |  |  |          return MP_VAL; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-10-15 19:57:12 +02:00
										 |  |  |    } while (d == 0u); | 
					
						
							| 
									
										
										
										
											2003-02-28 16:08:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 20:23:46 +02:00
										 |  |  |    if ((res = mp_add_d(a, d, a)) != MP_OKAY) { | 
					
						
							| 
									
										
										
										
											2003-02-28 16:08:34 +00:00
										 |  |  |       return res; | 
					
						
							| 
									
										
										
										
											2017-08-30 20:23:46 +02:00
										 |  |  |    } | 
					
						
							| 
									
										
										
										
											2003-02-28 16:09:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 20:23:46 +02:00
										 |  |  |    while (--digits > 0) { | 
					
						
							|  |  |  |       if ((res = mp_lshd(a, 1)) != MP_OKAY) { | 
					
						
							|  |  |  |          return res; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-14 14:33:36 +02:00
										 |  |  |       if (s_gen_random(&d) != MP_OKAY) { | 
					
						
							|  |  |  |          return MP_VAL; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if ((res = mp_add_d(a, d, a)) != MP_OKAY) { | 
					
						
							| 
									
										
										
										
											2017-08-30 20:23:46 +02:00
										 |  |  |          return res; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |    } | 
					
						
							| 
									
										
										
										
											2003-02-28 16:08:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 20:23:46 +02:00
										 |  |  |    return MP_OKAY; | 
					
						
							| 
									
										
										
										
											2003-02-28 16:08:34 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2004-10-29 22:07:18 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2005-08-01 16:37:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 16:27:26 +02:00
										 |  |  | /* ref:         $Format:%D$ */ | 
					
						
							|  |  |  | /* git commit:  $Format:%H$ */ | 
					
						
							|  |  |  | /* commit time: $Format:%ai$ */ |