Coverage Report

Created: 2025-08-28 06:59

/src/boringssl/crypto/fipsmodule/bn/bytes.cc.inc
Line
Count
Source (jump to first uncovered line)
1
// Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <openssl/bn.h>
16
17
#include <assert.h>
18
#include <limits.h>
19
20
#include "internal.h"
21
22
void bn_big_endian_to_words(BN_ULONG *out, size_t out_len, const uint8_t *in,
23
656k
                            size_t in_len) {
24
  // The caller should have sized |out| to fit |in| without truncating. This
25
  // condition ensures we do not overflow |out|, so use a runtime check.
26
656k
  BSSL_CHECK(in_len <= out_len * sizeof(BN_ULONG));
27
28
  // Load whole words.
29
12.1M
  while (in_len >= sizeof(BN_ULONG)) {
30
11.5M
    in_len -= sizeof(BN_ULONG);
31
11.5M
    out[0] = CRYPTO_load_word_be(in + in_len);
32
11.5M
    out++;
33
11.5M
    out_len--;
34
11.5M
  }
35
36
  // Load the last partial word.
37
656k
  if (in_len != 0) {
38
362k
    BN_ULONG word = 0;
39
1.10M
    for (size_t i = 0; i < in_len; i++) {
40
737k
      word = (word << 8) | in[i];
41
737k
    }
42
362k
    out[0] = word;
43
362k
    out++;
44
362k
    out_len--;
45
362k
  }
46
47
  // Fill the remainder with zeros.
48
656k
  OPENSSL_memset(out, 0, out_len * sizeof(BN_ULONG));
49
656k
}
50
51
452k
BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
52
452k
  BIGNUM *bn = NULL;
53
452k
  if (ret == NULL) {
54
13.5k
    bn = BN_new();
55
13.5k
    if (bn == NULL) {
56
0
      return NULL;
57
0
    }
58
13.5k
    ret = bn;
59
13.5k
  }
60
61
452k
  if (len == 0) {
62
45
    ret->width = 0;
63
45
    return ret;
64
45
  }
65
66
452k
  size_t num_words = ((len - 1) / BN_BYTES) + 1;
67
452k
  if (!bn_wexpand(ret, num_words)) {
68
0
    BN_free(bn);
69
0
    return NULL;
70
0
  }
71
72
  // |bn_wexpand| must check bounds on |num_words| to write it into
73
  // |ret->dmax|.
74
452k
  assert(num_words <= INT_MAX);
75
452k
  ret->width = (int)num_words;
76
452k
  ret->neg = 0;
77
78
452k
  bn_big_endian_to_words(ret->d, ret->width, in, len);
79
452k
  return ret;
80
452k
}
81
82
0
BIGNUM *BN_lebin2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
83
0
  BIGNUM *bn = NULL;
84
0
  if (ret == NULL) {
85
0
    bn = BN_new();
86
0
    if (bn == NULL) {
87
0
      return NULL;
88
0
    }
89
0
    ret = bn;
90
0
  }
91
92
0
  if (len == 0) {
93
0
    ret->width = 0;
94
0
    ret->neg = 0;
95
0
    return ret;
96
0
  }
97
98
  // Reserve enough space in |ret|.
99
0
  size_t num_words = ((len - 1) / BN_BYTES) + 1;
100
0
  if (!bn_wexpand(ret, num_words)) {
101
0
    BN_free(bn);
102
0
    return NULL;
103
0
  }
104
0
  ret->width = (int)num_words;
105
106
  // Make sure the top bytes will be zeroed.
107
0
  ret->d[num_words - 1] = 0;
108
109
  // We only support little-endian platforms, so we can simply memcpy the
110
  // internal representation.
111
0
  OPENSSL_memcpy(ret->d, in, len);
112
0
  return ret;
113
0
}
114
115
0
BIGNUM *BN_le2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
116
0
  return BN_lebin2bn(in, len, ret);
117
0
}
118
119
// fits_in_bytes returns one if the |num_words| words in |words| can be
120
// represented in |num_bytes| bytes.
121
static int fits_in_bytes(const BN_ULONG *words, size_t num_words,
122
444k
                         size_t num_bytes) {
123
444k
  const uint8_t *bytes = (const uint8_t *)words;
124
444k
  size_t tot_bytes = num_words * sizeof(BN_ULONG);
125
444k
  uint8_t mask = 0;
126
1.29M
  for (size_t i = num_bytes; i < tot_bytes; i++) {
127
848k
    mask |= bytes[i];
128
848k
  }
129
444k
  return mask == 0;
130
444k
}
131
132
82.7k
void bn_assert_fits_in_bytes(const BIGNUM *bn, size_t num) {
133
82.7k
  const uint8_t *bytes = (const uint8_t *)bn->d;
134
82.7k
  size_t tot_bytes = bn->width * sizeof(BN_ULONG);
135
82.7k
  if (tot_bytes > num) {
136
41.3k
    CONSTTIME_DECLASSIFY(bytes + num, tot_bytes - num);
137
372k
    for (size_t i = num; i < tot_bytes; i++) {
138
331k
      assert(bytes[i] == 0);
139
331k
    }
140
41.3k
    (void)bytes;
141
41.3k
  }
142
82.7k
}
143
144
void bn_words_to_big_endian(uint8_t *out, size_t out_len, const BN_ULONG *in,
145
285k
                            size_t in_len) {
146
  // The caller should have selected an output length without truncation.
147
285k
  declassify_assert(fits_in_bytes(in, in_len, out_len));
148
149
  // We only support little-endian platforms, so the internal representation is
150
  // also little-endian as bytes. We can simply copy it in reverse.
151
285k
  const uint8_t *bytes = (const uint8_t *)in;
152
285k
  size_t num_bytes = in_len * sizeof(BN_ULONG);
153
285k
  if (out_len < num_bytes) {
154
67.9k
    num_bytes = out_len;
155
67.9k
  }
156
157
24.3M
  for (size_t i = 0; i < num_bytes; i++) {
158
24.0M
    out[out_len - i - 1] = bytes[i];
159
24.0M
  }
160
  // Pad out the rest of the buffer with zeroes.
161
285k
  OPENSSL_memset(out, 0, out_len - num_bytes);
162
285k
}
163
164
2.45k
size_t BN_bn2bin(const BIGNUM *in, uint8_t *out) {
165
2.45k
  size_t n = BN_num_bytes(in);
166
2.45k
  bn_words_to_big_endian(out, n, in->d, in->width);
167
2.45k
  return n;
168
2.45k
}
169
170
0
int BN_bn2le_padded(uint8_t *out, size_t len, const BIGNUM *in) {
171
0
  if (!fits_in_bytes(in->d, in->width, len)) {
172
0
    return 0;
173
0
  }
174
175
  // We only support little-endian platforms, so we can simply memcpy into the
176
  // internal representation.
177
0
  const uint8_t *bytes = (const uint8_t *)in->d;
178
0
  size_t num_bytes = in->width * BN_BYTES;
179
0
  if (len < num_bytes) {
180
0
    num_bytes = len;
181
0
  }
182
183
0
  OPENSSL_memcpy(out, bytes, num_bytes);
184
  // Pad out the rest of the buffer with zeroes.
185
0
  OPENSSL_memset(out + num_bytes, 0, len - num_bytes);
186
0
  return 1;
187
0
}
188
189
158k
int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in) {
190
158k
  if (!fits_in_bytes(in->d, in->width, len)) {
191
2.03k
    return 0;
192
2.03k
  }
193
194
156k
  bn_words_to_big_endian(out, len, in->d, in->width);
195
156k
  return 1;
196
158k
}
197
198
0
BN_ULONG BN_get_word(const BIGNUM *bn) {
199
0
  switch (bn_minimal_width(bn)) {
200
0
    case 0:
201
0
      return 0;
202
0
    case 1:
203
0
      return bn->d[0];
204
0
    default:
205
0
      return BN_MASK2;
206
0
  }
207
0
}
208
209
1.41k
int BN_get_u64(const BIGNUM *bn, uint64_t *out) {
210
1.41k
  switch (bn_minimal_width(bn)) {
211
0
    case 0:
212
0
      *out = 0;
213
0
      return 1;
214
705
    case 1:
215
705
      *out = bn->d[0];
216
705
      return 1;
217
#if defined(OPENSSL_32_BIT)
218
    case 2:
219
      *out = (uint64_t) bn->d[0] | (((uint64_t) bn->d[1]) << 32);
220
      return 1;
221
#endif
222
705
    default:
223
705
      return 0;
224
1.41k
  }
225
1.41k
}