Coverage Report

Created: 2024-11-21 07:03

/src/boringssl/crypto/fipsmodule/bn/bytes.c.inc
Line
Count
Source (jump to first uncovered line)
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
#include <openssl/bn.h>
58
59
#include <assert.h>
60
#include <limits.h>
61
62
#include "internal.h"
63
64
void bn_big_endian_to_words(BN_ULONG *out, size_t out_len, const uint8_t *in,
65
25.4k
                            size_t in_len) {
66
  // The caller should have sized |out| to fit |in| without truncating. This
67
  // condition ensures we do not overflow |out|, so use a runtime check.
68
25.4k
  BSSL_CHECK(in_len <= out_len * sizeof(BN_ULONG));
69
70
  // Load whole words.
71
310k
  while (in_len >= sizeof(BN_ULONG)) {
72
284k
    in_len -= sizeof(BN_ULONG);
73
284k
    out[0] = CRYPTO_load_word_be(in + in_len);
74
284k
    out++;
75
284k
    out_len--;
76
284k
  }
77
78
  // Load the last partial word.
79
25.4k
  if (in_len != 0) {
80
21.8k
    BN_ULONG word = 0;
81
101k
    for (size_t i = 0; i < in_len; i++) {
82
79.8k
      word = (word << 8) | in[i];
83
79.8k
    }
84
21.8k
    out[0] = word;
85
21.8k
    out++;
86
21.8k
    out_len--;
87
21.8k
  }
88
89
  // Fill the remainder with zeros.
90
25.4k
  OPENSSL_memset(out, 0, out_len * sizeof(BN_ULONG));
91
25.4k
}
92
93
27.0k
BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
94
27.0k
  BIGNUM *bn = NULL;
95
27.0k
  if (ret == NULL) {
96
5.49k
    bn = BN_new();
97
5.49k
    if (bn == NULL) {
98
0
      return NULL;
99
0
    }
100
5.49k
    ret = bn;
101
5.49k
  }
102
103
27.0k
  if (len == 0) {
104
2.32k
    ret->width = 0;
105
2.32k
    return ret;
106
2.32k
  }
107
108
24.7k
  size_t num_words = ((len - 1) / BN_BYTES) + 1;
109
24.7k
  if (!bn_wexpand(ret, num_words)) {
110
0
    BN_free(bn);
111
0
    return NULL;
112
0
  }
113
114
  // |bn_wexpand| must check bounds on |num_words| to write it into
115
  // |ret->dmax|.
116
24.7k
  assert(num_words <= INT_MAX);
117
24.7k
  ret->width = (int)num_words;
118
24.7k
  ret->neg = 0;
119
120
24.7k
  bn_big_endian_to_words(ret->d, ret->width, in, len);
121
24.7k
  return ret;
122
24.7k
}
123
124
0
BIGNUM *BN_lebin2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
125
0
  BIGNUM *bn = NULL;
126
0
  if (ret == NULL) {
127
0
    bn = BN_new();
128
0
    if (bn == NULL) {
129
0
      return NULL;
130
0
    }
131
0
    ret = bn;
132
0
  }
133
134
0
  if (len == 0) {
135
0
    ret->width = 0;
136
0
    ret->neg = 0;
137
0
    return ret;
138
0
  }
139
140
  // Reserve enough space in |ret|.
141
0
  size_t num_words = ((len - 1) / BN_BYTES) + 1;
142
0
  if (!bn_wexpand(ret, num_words)) {
143
0
    BN_free(bn);
144
0
    return NULL;
145
0
  }
146
0
  ret->width = (int)num_words;
147
148
  // Make sure the top bytes will be zeroed.
149
0
  ret->d[num_words - 1] = 0;
150
151
  // We only support little-endian platforms, so we can simply memcpy the
152
  // internal representation.
153
0
  OPENSSL_memcpy(ret->d, in, len);
154
0
  return ret;
155
0
}
156
157
0
BIGNUM *BN_le2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
158
0
  return BN_lebin2bn(in, len, ret);
159
0
}
160
161
// fits_in_bytes returns one if the |num_words| words in |words| can be
162
// represented in |num_bytes| bytes.
163
static int fits_in_bytes(const BN_ULONG *words, size_t num_words,
164
17.9k
                         size_t num_bytes) {
165
17.9k
  const uint8_t *bytes = (const uint8_t *)words;
166
17.9k
  size_t tot_bytes = num_words * sizeof(BN_ULONG);
167
17.9k
  uint8_t mask = 0;
168
70.9k
  for (size_t i = num_bytes; i < tot_bytes; i++) {
169
53.0k
    mask |= bytes[i];
170
53.0k
  }
171
17.9k
  return mask == 0;
172
17.9k
}
173
174
0
void bn_assert_fits_in_bytes(const BIGNUM *bn, size_t num) {
175
0
  const uint8_t *bytes = (const uint8_t *)bn->d;
176
0
  size_t tot_bytes = bn->width * sizeof(BN_ULONG);
177
0
  if (tot_bytes > num) {
178
0
    CONSTTIME_DECLASSIFY(bytes + num, tot_bytes - num);
179
0
    for (size_t i = num; i < tot_bytes; i++) {
180
0
      assert(bytes[i] == 0);
181
0
    }
182
0
    (void)bytes;
183
0
  }
184
0
}
185
186
void bn_words_to_big_endian(uint8_t *out, size_t out_len, const BN_ULONG *in,
187
11.6k
                            size_t in_len) {
188
  // The caller should have selected an output length without truncation.
189
11.6k
  declassify_assert(fits_in_bytes(in, in_len, out_len));
190
191
  // We only support little-endian platforms, so the internal representation is
192
  // also little-endian as bytes. We can simply copy it in reverse.
193
11.6k
  const uint8_t *bytes = (const uint8_t *)in;
194
11.6k
  size_t num_bytes = in_len * sizeof(BN_ULONG);
195
11.6k
  if (out_len < num_bytes) {
196
5.29k
    num_bytes = out_len;
197
5.29k
  }
198
199
1.64M
  for (size_t i = 0; i < num_bytes; i++) {
200
1.63M
    out[out_len - i - 1] = bytes[i];
201
1.63M
  }
202
  // Pad out the rest of the buffer with zeroes.
203
11.6k
  OPENSSL_memset(out, 0, out_len - num_bytes);
204
11.6k
}
205
206
21.0k
size_t BN_bn2bin(const BIGNUM *in, uint8_t *out) {
207
21.0k
  size_t n = BN_num_bytes(in);
208
21.0k
  bn_words_to_big_endian(out, n, in->d, in->width);
209
21.0k
  return n;
210
21.0k
}
211
212
0
int BN_bn2le_padded(uint8_t *out, size_t len, const BIGNUM *in) {
213
0
  if (!fits_in_bytes(in->d, in->width, len)) {
214
0
    return 0;
215
0
  }
216
217
  // We only support little-endian platforms, so we can simply memcpy into the
218
  // internal representation.
219
0
  const uint8_t *bytes = (const uint8_t *)in->d;
220
0
  size_t num_bytes = in->width * BN_BYTES;
221
0
  if (len < num_bytes) {
222
0
    num_bytes = len;
223
0
  }
224
225
0
  OPENSSL_memcpy(out, bytes, num_bytes);
226
  // Pad out the rest of the buffer with zeroes.
227
0
  OPENSSL_memset(out + num_bytes, 0, len - num_bytes);
228
0
  return 1;
229
0
}
230
231
6.37k
int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in) {
232
6.37k
  if (!fits_in_bytes(in->d, in->width, len)) {
233
5
    return 0;
234
5
  }
235
236
6.37k
  bn_words_to_big_endian(out, len, in->d, in->width);
237
6.37k
  return 1;
238
6.37k
}
239
240
0
BN_ULONG BN_get_word(const BIGNUM *bn) {
241
0
  switch (bn_minimal_width(bn)) {
242
0
    case 0:
243
0
      return 0;
244
0
    case 1:
245
0
      return bn->d[0];
246
0
    default:
247
0
      return BN_MASK2;
248
0
  }
249
0
}
250
251
0
int BN_get_u64(const BIGNUM *bn, uint64_t *out) {
252
0
  switch (bn_minimal_width(bn)) {
253
0
    case 0:
254
0
      *out = 0;
255
0
      return 1;
256
0
    case 1:
257
0
      *out = bn->d[0];
258
0
      return 1;
259
#if defined(OPENSSL_32_BIT)
260
    case 2:
261
      *out = (uint64_t) bn->d[0] | (((uint64_t) bn->d[1]) << 32);
262
      return 1;
263
#endif
264
0
    default:
265
0
      return 0;
266
0
  }
267
0
}