comparison libtommath/bn_mp_rand.c @ 1655:f52919ffd3b1

update ltm to 1.1.0 and enable FIPS 186.4 compliant key-generation (#79) * make key-generation compliant to FIPS 186.4 * fix includes in tommath_class.h * update fuzzcorpus instead of error-out * fixup fuzzing make-targets * update Makefile.in * apply necessary patches to ltm sources * clean-up not required ltm files * update to vanilla ltm 1.1.0 this already only contains the required files * remove set/get double
author Steffen Jaeckel <s_jaeckel@gmx.de>
date Mon, 16 Sep 2019 15:50:38 +0200
parents 8bba51a55704
children 1051e4eea25a
comparison
equal deleted inserted replaced
1654:cc0fc5131c5c 1655:f52919ffd3b1
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 *
5 * LibTomMath is a library that provides multiple-precision 5 * LibTomMath is a library that provides multiple-precision
6 * integer arithmetic as well as number theoretic functionality. 6 * integer arithmetic as well as number theoretic functionality.
7 * 7 *
8 * The library was designed directly after the MPI library by 8 * The library was designed directly after the MPI library by
9 * Michael Fromberger but has been written from scratch with 9 * Michael Fromberger but has been written from scratch with
10 * additional optimizations in place. 10 * additional optimizations in place.
11 * 11 *
12 * The library is free for all purposes without any express 12 * SPDX-License-Identifier: Unlicense
13 * guarantee it works.
14 *
15 * Tom St Denis, [email protected], http://libtom.org
16 */ 13 */
17 14
18 #if MP_GEN_RANDOM_MAX == 0xffffffff 15 /* First the OS-specific special cases
19 #define MP_GEN_RANDOM_SHIFT 32 16 * - *BSD
20 #elif MP_GEN_RANDOM_MAX == 32767 17 * - Windows
21 /* SHRT_MAX */ 18 */
22 #define MP_GEN_RANDOM_SHIFT 15 19 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
23 #elif MP_GEN_RANDOM_MAX == 2147483647 20 #define MP_ARC4RANDOM
24 /* INT_MAX */ 21 #define MP_GEN_RANDOM_MAX 0xffffffffu
25 #define MP_GEN_RANDOM_SHIFT 31 22 #define MP_GEN_RANDOM_SHIFT 32
26 #elif !defined(MP_GEN_RANDOM_SHIFT) 23
27 #error Thou shalt define their own valid MP_GEN_RANDOM_SHIFT 24 static int s_read_arc4random(mp_digit *p)
28 #endif 25 {
26 mp_digit d = 0, msk = 0;
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 }
60
61 static int s_read_win_csp(mp_digit *p)
62 {
63 int ret = -1;
64 if (hProv == 0) {
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 }
29 173
30 /* makes a pseudo-random int of a given size */ 174 /* makes a pseudo-random int of a given size */
31 static mp_digit s_gen_random(void) 175 int mp_rand_digit(mp_digit *r)
32 { 176 {
33 mp_digit d = 0, msk = 0; 177 int ret = s_rand_digit(r);
34 do { 178 *r &= MP_MASK;
35 d <<= MP_GEN_RANDOM_SHIFT; 179 return ret;
36 d |= ((mp_digit) MP_GEN_RANDOM()); 180 }
37 msk <<= MP_GEN_RANDOM_SHIFT; 181
38 msk |= (MP_MASK & MP_GEN_RANDOM_MAX); 182 int mp_rand(mp_int *a, int digits)
39 } while ((MP_MASK & msk) != MP_MASK); 183 {
40 d &= MP_MASK; 184 int res;
41 return d; 185 mp_digit d;
42 } 186
43 187 mp_zero(a);
44 int 188 if (digits <= 0) {
45 mp_rand (mp_int * a, int digits) 189 return MP_OKAY;
46 { 190 }
47 int res; 191
48 mp_digit d; 192 /* first place a random non-zero digit */
49 193 do {
50 mp_zero (a); 194 if (mp_rand_digit(&d) != MP_OKAY) {
51 if (digits <= 0) { 195 return MP_VAL;
52 return MP_OKAY; 196 }
53 } 197 } while (d == 0u);
54 198
55 /* first place a random non-zero digit */ 199 if ((res = mp_add_d(a, d, a)) != MP_OKAY) {
56 do {
57 d = s_gen_random();
58 } while (d == 0);
59
60 if ((res = mp_add_d (a, d, a)) != MP_OKAY) {
61 return res;
62 }
63
64 while (--digits > 0) {
65 if ((res = mp_lshd (a, 1)) != MP_OKAY) {
66 return res; 200 return res;
67 } 201 }
68 202
69 if ((res = mp_add_d (a, s_gen_random(), a)) != MP_OKAY) { 203 while (--digits > 0) {
70 return res; 204 if ((res = mp_lshd(a, 1)) != MP_OKAY) {
71 } 205 return res;
72 } 206 }
73 207
74 return MP_OKAY; 208 if (mp_rand_digit(&d) != MP_OKAY) {
75 } 209 return MP_VAL;
76 #endif 210 }
77 211 if ((res = mp_add_d(a, d, a)) != MP_OKAY) {
78 /* ref: $Format:%D$ */ 212 return res;
79 /* git commit: $Format:%H$ */ 213 }
80 /* commit time: $Format:%ai$ */ 214 }
215
216 return MP_OKAY;
217 }
218 #endif
219
220 /* ref: HEAD -> master, tag: v1.1.0 */
221 /* git commit: 08549ad6bc8b0cede0b357a9c341c5c6473a9c55 */
222 /* commit time: 2019-01-28 20:32:32 +0100 */