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