1 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
2 | * All rights reserved. |
3 | * |
4 | * This package is an SSL implementation written |
5 | * by Eric Young (eay@cryptsoft.com). |
6 | * The implementation was written so as to conform with Netscapes SSL. |
7 | * |
8 | * This library is free for commercial and non-commercial use as long as |
9 | * the following conditions are aheared to. The following conditions |
10 | * apply to all code found in this distribution, be it the RC4, RSA, |
11 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation |
12 | * included with this distribution is covered by the same copyright terms |
13 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). |
14 | * |
15 | * Copyright remains Eric Young's, and as such any Copyright notices in |
16 | * the code are not to be removed. |
17 | * If this package is used in a product, Eric Young should be given attribution |
18 | * as the author of the parts of the library used. |
19 | * This can be in the form of a textual message at program startup or |
20 | * in documentation (online or textual) provided with the package. |
21 | * |
22 | * Redistribution and use in source and binary forms, with or without |
23 | * modification, are permitted provided that the following conditions |
24 | * are met: |
25 | * 1. Redistributions of source code must retain the copyright |
26 | * notice, this list of conditions and the following disclaimer. |
27 | * 2. Redistributions in binary form must reproduce the above copyright |
28 | * notice, this list of conditions and the following disclaimer in the |
29 | * documentation and/or other materials provided with the distribution. |
30 | * 3. All advertising materials mentioning features or use of this software |
31 | * must display the following acknowledgement: |
32 | * "This product includes cryptographic software written by |
33 | * Eric Young (eay@cryptsoft.com)" |
34 | * The word 'cryptographic' can be left out if the rouines from the library |
35 | * being used are not cryptographic related :-). |
36 | * 4. If you include any Windows specific code (or a derivative thereof) from |
37 | * the apps directory (application code) you must include an acknowledgement: |
38 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" |
39 | * |
40 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
41 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
42 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
43 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
44 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
45 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
46 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
47 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
48 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
49 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
50 | * SUCH DAMAGE. |
51 | * |
52 | * The licence and distribution terms for any publically available version or |
53 | * derivative of this code cannot be changed. i.e. this code cannot simply be |
54 | * copied and put under another distribution licence |
55 | * [including the GNU Public Licence.] |
56 | */ |
57 | /* ==================================================================== |
58 | * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. |
59 | * |
60 | * Redistribution and use in source and binary forms, with or without |
61 | * modification, are permitted provided that the following conditions |
62 | * are met: |
63 | * |
64 | * 1. Redistributions of source code must retain the above copyright |
65 | * notice, this list of conditions and the following disclaimer. |
66 | * |
67 | * 2. Redistributions in binary form must reproduce the above copyright |
68 | * notice, this list of conditions and the following disclaimer in |
69 | * the documentation and/or other materials provided with the |
70 | * distribution. |
71 | * |
72 | * 3. All advertising materials mentioning features or use of this |
73 | * software must display the following acknowledgment: |
74 | * "This product includes software developed by the OpenSSL Project |
75 | * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" |
76 | * |
77 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
78 | * endorse or promote products derived from this software without |
79 | * prior written permission. For written permission, please contact |
80 | * openssl-core@openssl.org. |
81 | * |
82 | * 5. Products derived from this software may not be called "OpenSSL" |
83 | * nor may "OpenSSL" appear in their names without prior written |
84 | * permission of the OpenSSL Project. |
85 | * |
86 | * 6. Redistributions of any form whatsoever must retain the following |
87 | * acknowledgment: |
88 | * "This product includes software developed by the OpenSSL Project |
89 | * for use in the OpenSSL Toolkit (http://www.openssl.org/)" |
90 | * |
91 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
92 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
93 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
94 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
95 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
96 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
97 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
98 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
99 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
100 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
101 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
102 | * OF THE POSSIBILITY OF SUCH DAMAGE. |
103 | * ==================================================================== |
104 | * |
105 | * This product includes cryptographic software written by Eric Young |
106 | * (eay@cryptsoft.com). This product includes software written by Tim |
107 | * Hudson (tjh@cryptsoft.com). */ |
108 | |
109 | #include <openssl/bn.h> |
110 | |
111 | #include <limits.h> |
112 | #include <string.h> |
113 | |
114 | #include <openssl/err.h> |
115 | #include <openssl/rand.h> |
116 | #include <openssl/type_check.h> |
117 | |
118 | #include "internal.h" |
119 | #include "../../internal.h" |
120 | #include "../rand/internal.h" |
121 | |
122 | |
123 | int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) { |
124 | if (rnd == NULL) { |
125 | return 0; |
126 | } |
127 | |
128 | if (top != BN_RAND_TOP_ANY && top != BN_RAND_TOP_ONE && |
129 | top != BN_RAND_TOP_TWO) { |
130 | OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
131 | return 0; |
132 | } |
133 | |
134 | if (bottom != BN_RAND_BOTTOM_ANY && bottom != BN_RAND_BOTTOM_ODD) { |
135 | OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
136 | return 0; |
137 | } |
138 | |
139 | if (bits == 0) { |
140 | BN_zero(rnd); |
141 | return 1; |
142 | } |
143 | |
144 | if (bits > INT_MAX - (BN_BITS2 - 1)) { |
145 | OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG); |
146 | return 0; |
147 | } |
148 | |
149 | int words = (bits + BN_BITS2 - 1) / BN_BITS2; |
150 | int bit = (bits - 1) % BN_BITS2; |
151 | const BN_ULONG kOne = 1; |
152 | const BN_ULONG kThree = 3; |
153 | BN_ULONG mask = bit < BN_BITS2 - 1 ? (kOne << (bit + 1)) - 1 : BN_MASK2; |
154 | if (!bn_wexpand(rnd, words)) { |
155 | return 0; |
156 | } |
157 | |
158 | RAND_bytes((uint8_t *)rnd->d, words * sizeof(BN_ULONG)); |
159 | rnd->d[words - 1] &= mask; |
160 | if (top != BN_RAND_TOP_ANY) { |
161 | if (top == BN_RAND_TOP_TWO && bits > 1) { |
162 | if (bit == 0) { |
163 | rnd->d[words - 1] |= 1; |
164 | rnd->d[words - 2] |= kOne << (BN_BITS2 - 1); |
165 | } else { |
166 | rnd->d[words - 1] |= kThree << (bit - 1); |
167 | } |
168 | } else { |
169 | rnd->d[words - 1] |= kOne << bit; |
170 | } |
171 | } |
172 | if (bottom == BN_RAND_BOTTOM_ODD) { |
173 | rnd->d[0] |= 1; |
174 | } |
175 | |
176 | rnd->neg = 0; |
177 | rnd->width = words; |
178 | return 1; |
179 | } |
180 | |
181 | int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom) { |
182 | return BN_rand(rnd, bits, top, bottom); |
183 | } |
184 | |
185 | // bn_less_than_word_mask returns a mask of all ones if the number represented |
186 | // by |len| words at |a| is less than |b| and zero otherwise. It performs this |
187 | // computation in time independent of the value of |a|. |b| is assumed public. |
188 | static crypto_word_t bn_less_than_word_mask(const BN_ULONG *a, size_t len, |
189 | BN_ULONG b) { |
190 | if (b == 0) { |
191 | return CONSTTIME_FALSE_W; |
192 | } |
193 | if (len == 0) { |
194 | return CONSTTIME_TRUE_W; |
195 | } |
196 | |
197 | // |a| < |b| iff a[1..len-1] are all zero and a[0] < b. |
198 | OPENSSL_STATIC_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t), |
199 | "crypto_word_t is too small" ); |
200 | crypto_word_t mask = 0; |
201 | for (size_t i = 1; i < len; i++) { |
202 | mask |= a[i]; |
203 | } |
204 | // |mask| is now zero iff a[1..len-1] are all zero. |
205 | mask = constant_time_is_zero_w(mask); |
206 | mask &= constant_time_lt_w(a[0], b); |
207 | return mask; |
208 | } |
209 | |
210 | int bn_in_range_words(const BN_ULONG *a, BN_ULONG min_inclusive, |
211 | const BN_ULONG *max_exclusive, size_t len) { |
212 | crypto_word_t mask = ~bn_less_than_word_mask(a, len, min_inclusive); |
213 | return mask & bn_less_than_words(a, max_exclusive, len); |
214 | } |
215 | |
216 | static int bn_range_to_mask(size_t *out_words, BN_ULONG *out_mask, |
217 | size_t min_inclusive, const BN_ULONG *max_exclusive, |
218 | size_t len) { |
219 | // The magnitude of |max_exclusive| is assumed public. |
220 | size_t words = len; |
221 | while (words > 0 && max_exclusive[words - 1] == 0) { |
222 | words--; |
223 | } |
224 | if (words == 0 || |
225 | (words == 1 && max_exclusive[0] <= min_inclusive)) { |
226 | OPENSSL_PUT_ERROR(BN, BN_R_INVALID_RANGE); |
227 | return 0; |
228 | } |
229 | BN_ULONG mask = max_exclusive[words - 1]; |
230 | // This sets all bits in |mask| below the most significant bit. |
231 | mask |= mask >> 1; |
232 | mask |= mask >> 2; |
233 | mask |= mask >> 4; |
234 | mask |= mask >> 8; |
235 | mask |= mask >> 16; |
236 | #if defined(OPENSSL_64_BIT) |
237 | mask |= mask >> 32; |
238 | #endif |
239 | |
240 | *out_words = words; |
241 | *out_mask = mask; |
242 | return 1; |
243 | } |
244 | |
245 | int bn_rand_range_words(BN_ULONG *out, BN_ULONG min_inclusive, |
246 | const BN_ULONG *max_exclusive, size_t len, |
247 | const uint8_t additional_data[32]) { |
248 | // This function implements the equivalent of steps 4 through 7 of FIPS 186-4 |
249 | // appendices B.4.2 and B.5.2. When called in those contexts, |max_exclusive| |
250 | // is n and |min_inclusive| is one. |
251 | |
252 | // Compute the bit length of |max_exclusive| (step 1), in terms of a number of |
253 | // |words| worth of entropy to fill and a mask of bits to clear in the top |
254 | // word. |
255 | size_t words; |
256 | BN_ULONG mask; |
257 | if (!bn_range_to_mask(&words, &mask, min_inclusive, max_exclusive, len)) { |
258 | return 0; |
259 | } |
260 | |
261 | // Fill any unused words with zero. |
262 | OPENSSL_memset(out + words, 0, (len - words) * sizeof(BN_ULONG)); |
263 | |
264 | unsigned count = 100; |
265 | do { |
266 | if (!--count) { |
267 | OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); |
268 | return 0; |
269 | } |
270 | |
271 | // Steps 4 and 5. Use |words| and |mask| together to obtain a string of N |
272 | // bits, where N is the bit length of |max_exclusive|. |
273 | RAND_bytes_with_additional_data((uint8_t *)out, words * sizeof(BN_ULONG), |
274 | additional_data); |
275 | out[words - 1] &= mask; |
276 | |
277 | // If out >= max_exclusive or out < min_inclusive, retry. This implements |
278 | // the equivalent of steps 6 and 7 without leaking the value of |out|. |
279 | } while (!bn_in_range_words(out, min_inclusive, max_exclusive, words)); |
280 | return 1; |
281 | } |
282 | |
283 | int BN_rand_range_ex(BIGNUM *r, BN_ULONG min_inclusive, |
284 | const BIGNUM *max_exclusive) { |
285 | static const uint8_t kDefaultAdditionalData[32] = {0}; |
286 | if (!bn_wexpand(r, max_exclusive->width) || |
287 | !bn_rand_range_words(r->d, min_inclusive, max_exclusive->d, |
288 | max_exclusive->width, kDefaultAdditionalData)) { |
289 | return 0; |
290 | } |
291 | |
292 | r->neg = 0; |
293 | r->width = max_exclusive->width; |
294 | return 1; |
295 | } |
296 | |
297 | int bn_rand_secret_range(BIGNUM *r, int *out_is_uniform, BN_ULONG min_inclusive, |
298 | const BIGNUM *max_exclusive) { |
299 | size_t words; |
300 | BN_ULONG mask; |
301 | if (!bn_range_to_mask(&words, &mask, min_inclusive, max_exclusive->d, |
302 | max_exclusive->width) || |
303 | !bn_wexpand(r, words)) { |
304 | return 0; |
305 | } |
306 | |
307 | assert(words > 0); |
308 | assert(mask != 0); |
309 | // The range must be large enough for bit tricks to fix invalid values. |
310 | if (words == 1 && min_inclusive > mask >> 1) { |
311 | OPENSSL_PUT_ERROR(BN, BN_R_INVALID_RANGE); |
312 | return 0; |
313 | } |
314 | |
315 | // Select a uniform random number with num_bits(max_exclusive) bits. |
316 | RAND_bytes((uint8_t *)r->d, words * sizeof(BN_ULONG)); |
317 | r->d[words - 1] &= mask; |
318 | |
319 | // Check, in constant-time, if the value is in range. |
320 | *out_is_uniform = |
321 | bn_in_range_words(r->d, min_inclusive, max_exclusive->d, words); |
322 | crypto_word_t in_range = *out_is_uniform; |
323 | in_range = 0 - in_range; |
324 | |
325 | // If the value is not in range, force it to be in range. |
326 | r->d[0] |= constant_time_select_w(in_range, 0, min_inclusive); |
327 | r->d[words - 1] &= constant_time_select_w(in_range, BN_MASK2, mask >> 1); |
328 | assert(bn_in_range_words(r->d, min_inclusive, max_exclusive->d, words)); |
329 | |
330 | r->neg = 0; |
331 | r->width = words; |
332 | return 1; |
333 | } |
334 | |
335 | int BN_rand_range(BIGNUM *r, const BIGNUM *range) { |
336 | return BN_rand_range_ex(r, 0, range); |
337 | } |
338 | |
339 | int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range) { |
340 | return BN_rand_range(r, range); |
341 | } |
342 | |