Mercurial > dropbear
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 */ |