comparison libtommath/bn_mp_rand.c @ 1692:1051e4eea25a

Update LibTomMath to 1.2.0 (#84) * update C files * update other files * update headers * update makefiles * remove mp_set/get_double() * use ltm 1.2.0 API * update ltm_desc * use bundled tommath if system-tommath is too old * XMALLOC etc. were changed to MP_MALLOC etc.
author Steffen Jaeckel <s@jaeckel.eu>
date Tue, 26 May 2020 17:36:47 +0200
parents f52919ffd3b1
children 34d9d3c022ce
comparison
equal deleted inserted replaced
1691:2d3745d58843 1692:1051e4eea25a
1 #include "tommath_private.h" 1 #include "tommath_private.h"
2 #ifdef BN_MP_RAND_C 2 #ifdef BN_MP_RAND_C
3 /* LibTomMath, multiple-precision integer library -- Tom St Denis 3 /* LibTomMath, multiple-precision integer library -- Tom St Denis */
4 * 4 /* SPDX-License-Identifier: Unlicense */
5 * LibTomMath is a library that provides multiple-precision
6 * integer arithmetic as well as number theoretic functionality.
7 *
8 * The library was designed directly after the MPI library by
9 * Michael Fromberger but has been written from scratch with
10 * additional optimizations in place.
11 *
12 * SPDX-License-Identifier: Unlicense
13 */
14 5
15 /* First the OS-specific special cases 6 mp_err(*s_mp_rand_source)(void *out, size_t size) = s_mp_rand_platform;
16 * - *BSD
17 * - Windows
18 */
19 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
20 #define MP_ARC4RANDOM
21 #define MP_GEN_RANDOM_MAX 0xffffffffu
22 #define MP_GEN_RANDOM_SHIFT 32
23 7
24 static int s_read_arc4random(mp_digit *p) 8 void mp_rand_source(mp_err(*source)(void *out, size_t size))
25 { 9 {
26 mp_digit d = 0, msk = 0; 10 s_mp_rand_source = (source == NULL) ? s_mp_rand_platform : source;
27 do {
28 d <<= MP_GEN_RANDOM_SHIFT;
29 d |= ((mp_digit) arc4random());
30 msk <<= MP_GEN_RANDOM_SHIFT;
31 msk |= (MP_MASK & MP_GEN_RANDOM_MAX);
32 } while ((MP_MASK & msk) != MP_MASK);
33 *p = d;
34 return MP_OKAY;
35 }
36 #endif
37
38 #if defined(_WIN32) || defined(_WIN32_WCE)
39 #define MP_WIN_CSP
40
41 #ifndef _WIN32_WINNT
42 #define _WIN32_WINNT 0x0400
43 #endif
44 #ifdef _WIN32_WCE
45 #define UNDER_CE
46 #define ARM
47 #endif
48
49 #define WIN32_LEAN_AND_MEAN
50 #include <windows.h>
51 #include <wincrypt.h>
52
53 static HCRYPTPROV hProv = 0;
54
55 static void s_cleanup_win_csp(void)
56 {
57 CryptReleaseContext(hProv, 0);
58 hProv = 0;
59 } 11 }
60 12
61 static int s_read_win_csp(mp_digit *p) 13 mp_err mp_rand(mp_int *a, int digits)
62 { 14 {
63 int ret = -1; 15 int i;
64 if (hProv == 0) { 16 mp_err err;
65 if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
66 (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) &&
67 !CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
68 CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) {
69 hProv = 0;
70 return ret;
71 }
72 atexit(s_cleanup_win_csp);
73 }
74 if (CryptGenRandom(hProv, sizeof(*p), (void *)p) == TRUE) {
75 ret = MP_OKAY;
76 }
77 return ret;
78 }
79 #endif /* WIN32 */
80
81 #if !defined(MP_WIN_CSP) && defined(__linux__) && defined(__GLIBC_PREREQ)
82 #if __GLIBC_PREREQ(2, 25)
83 #define MP_GETRANDOM
84 #include <sys/random.h>
85 #include <errno.h>
86
87 static int s_read_getrandom(mp_digit *p)
88 {
89 int ret;
90 do {
91 ret = getrandom(p, sizeof(*p), 0);
92 } while ((ret == -1) && (errno == EINTR));
93 if (ret == sizeof(*p)) return MP_OKAY;
94 return -1;
95 }
96 #endif
97 #endif
98
99 /* We assume all platforms besides windows provide "/dev/urandom".
100 * In case yours doesn't, define MP_NO_DEV_URANDOM at compile-time.
101 */
102 #if !defined(MP_WIN_CSP) && !defined(MP_NO_DEV_URANDOM)
103 #ifndef MP_DEV_URANDOM
104 #define MP_DEV_URANDOM "/dev/urandom"
105 #endif
106 #include <fcntl.h>
107 #include <errno.h>
108 #include <unistd.h>
109
110 static int s_read_dev_urandom(mp_digit *p)
111 {
112 ssize_t r;
113 int fd;
114 do {
115 fd = open(MP_DEV_URANDOM, O_RDONLY);
116 } while ((fd == -1) && (errno == EINTR));
117 if (fd == -1) return -1;
118 do {
119 r = read(fd, p, sizeof(*p));
120 } while ((r == -1) && (errno == EINTR));
121 close(fd);
122 if (r != sizeof(*p)) return -1;
123 return MP_OKAY;
124 }
125 #endif
126
127 #if defined(MP_PRNG_ENABLE_LTM_RNG)
128 unsigned long (*ltm_rng)(unsigned char *out, unsigned long outlen, void (*callback)(void));
129 void (*ltm_rng_callback)(void);
130
131 static int s_read_ltm_rng(mp_digit *p)
132 {
133 unsigned long ret;
134 if (ltm_rng == NULL) return -1;
135 ret = ltm_rng((void *)p, sizeof(*p), ltm_rng_callback);
136 if (ret != sizeof(*p)) return -1;
137 return MP_OKAY;
138 }
139 #endif
140
141 static int s_rand_digit(mp_digit *p)
142 {
143 int ret = -1;
144
145 #if defined(MP_ARC4RANDOM)
146 ret = s_read_arc4random(p);
147 if (ret == MP_OKAY) return ret;
148 #endif
149
150 #if defined(MP_WIN_CSP)
151 ret = s_read_win_csp(p);
152 if (ret == MP_OKAY) return ret;
153 #else
154
155 #if defined(MP_GETRANDOM)
156 ret = s_read_getrandom(p);
157 if (ret == MP_OKAY) return ret;
158 #endif
159 #if defined(MP_DEV_URANDOM)
160 ret = s_read_dev_urandom(p);
161 if (ret == MP_OKAY) return ret;
162 #endif
163
164 #endif /* MP_WIN_CSP */
165
166 #if defined(MP_PRNG_ENABLE_LTM_RNG)
167 ret = s_read_ltm_rng(p);
168 if (ret == MP_OKAY) return ret;
169 #endif
170
171 return ret;
172 }
173
174 /* makes a pseudo-random int of a given size */
175 int mp_rand_digit(mp_digit *r)
176 {
177 int ret = s_rand_digit(r);
178 *r &= MP_MASK;
179 return ret;
180 }
181
182 int mp_rand(mp_int *a, int digits)
183 {
184 int res;
185 mp_digit d;
186 17
187 mp_zero(a); 18 mp_zero(a);
19
188 if (digits <= 0) { 20 if (digits <= 0) {
189 return MP_OKAY; 21 return MP_OKAY;
190 } 22 }
191 23
192 /* first place a random non-zero digit */ 24 if ((err = mp_grow(a, digits)) != MP_OKAY) {
193 do { 25 return err;
194 if (mp_rand_digit(&d) != MP_OKAY) {
195 return MP_VAL;
196 }
197 } while (d == 0u);
198
199 if ((res = mp_add_d(a, d, a)) != MP_OKAY) {
200 return res;
201 } 26 }
202 27
203 while (--digits > 0) { 28 if ((err = s_mp_rand_source(a->dp, (size_t)digits * sizeof(mp_digit))) != MP_OKAY) {
204 if ((res = mp_lshd(a, 1)) != MP_OKAY) { 29 return err;
205 return res; 30 }
31
32 /* TODO: We ensure that the highest digit is nonzero. Should this be removed? */
33 while ((a->dp[digits - 1] & MP_MASK) == 0u) {
34 if ((err = s_mp_rand_source(a->dp + digits - 1, sizeof(mp_digit))) != MP_OKAY) {
35 return err;
206 } 36 }
37 }
207 38
208 if (mp_rand_digit(&d) != MP_OKAY) { 39 a->used = digits;
209 return MP_VAL; 40 for (i = 0; i < digits; ++i) {
210 } 41 a->dp[i] &= MP_MASK;
211 if ((res = mp_add_d(a, d, a)) != MP_OKAY) {
212 return res;
213 }
214 } 42 }
215 43
216 return MP_OKAY; 44 return MP_OKAY;
217 } 45 }
218 #endif 46 #endif
219
220 /* ref: HEAD -> master, tag: v1.1.0 */
221 /* git commit: 08549ad6bc8b0cede0b357a9c341c5c6473a9c55 */
222 /* commit time: 2019-01-28 20:32:32 +0100 */