1 // Copyright 2021 Google LLC
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 // http://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 ///////////////////////////////////////////////////////////////////////////////
16 #include "tink/internal/bn_util.h"
17
18 #include <stddef.h>
19
20 #include <memory>
21 #include <string>
22 #include <vector>
23
24 #include "gmock/gmock.h"
25 #include "gtest/gtest.h"
26 #include "absl/strings/escaping.h"
27 #include "absl/strings/str_cat.h"
28 #include "absl/strings/string_view.h"
29 #include "absl/types/span.h"
30 #include "openssl/bn.h"
31 #include "tink/internal/ssl_unique_ptr.h"
32 #include "tink/util/secret_data.h"
33 #include "tink/util/status.h"
34 #include "tink/util/statusor.h"
35 #include "tink/util/test_matchers.h"
36
37 namespace crypto {
38 namespace tink {
39 namespace internal {
40 namespace {
41
42 using ::crypto::tink::test::IsOk;
43 using ::testing::Not;
44
HexToBignum(absl::string_view bn_hex)45 util::StatusOr<internal::SslUniquePtr<BIGNUM>> HexToBignum(
46 absl::string_view bn_hex) {
47 BIGNUM* bn = nullptr;
48 BN_hex2bn(&bn, bn_hex.data());
49 return internal::SslUniquePtr<BIGNUM>(bn);
50 }
51
TEST(BnUtil,StringToBignum)52 TEST(BnUtil, StringToBignum) {
53 std::vector<std::string> bn_str = {"0000000000000000", "0000000000000001",
54 "1000000000000000", "ffffffffffffffff",
55 "0fffffffffffffff", "00ffffffffffffff"};
56 for (const std::string& s : bn_str) {
57 const std::string bn_bytes = absl::HexStringToBytes(s);
58 util::StatusOr<internal::SslUniquePtr<BIGNUM>> bn =
59 StringToBignum(bn_bytes);
60 ASSERT_THAT(bn, IsOk());
61
62 util::StatusOr<internal::SslUniquePtr<BIGNUM>> expected_bn = HexToBignum(s);
63 ASSERT_THAT(expected_bn, IsOk());
64 EXPECT_EQ(BN_cmp(expected_bn->get(), bn->get()), 0);
65 }
66 }
67
TEST(StringToBignum,IgnoresLeadingZeros)68 TEST(StringToBignum, IgnoresLeadingZeros) {
69 std::string encoded = absl::HexStringToBytes("0102");
70 std::string encoded_with_leading_zeros = absl::HexStringToBytes("0000000102");
71
72 util::StatusOr<internal::SslUniquePtr<BIGNUM>> num =
73 StringToBignum(encoded);
74 ASSERT_THAT(num, IsOk());
75
76 util::StatusOr<internal::SslUniquePtr<BIGNUM>> num2 =
77 StringToBignum(encoded_with_leading_zeros);
78 ASSERT_THAT(num2, IsOk());
79
80 EXPECT_EQ(BN_cmp(num2->get(), num->get()), 0);
81 }
82
TEST(BnUtil,BignumToString)83 TEST(BnUtil, BignumToString) {
84 std::vector<std::string> bn_strs = {"0000000000000000", "0000000000000001",
85 "1000000000000000", "ffffffffffffffff",
86 "0fffffffffffffff", "00ffffffffffffff"};
87 for (const std::string& s : bn_strs) {
88 util::StatusOr<internal::SslUniquePtr<BIGNUM>> expected_bn = HexToBignum(s);
89 ASSERT_THAT(expected_bn, IsOk());
90
91 const std::string bn_bytes = absl::HexStringToBytes(s);
92 util::StatusOr<std::string> result =
93 BignumToString(expected_bn->get(), bn_bytes.size());
94 ASSERT_THAT(result, IsOk());
95 EXPECT_EQ(bn_bytes, *result);
96 }
97 }
98
TEST(BignumToStringWithBNNumBytes,NoLeadingZeros)99 TEST(BignumToStringWithBNNumBytes, NoLeadingZeros) {
100 {
101 util::StatusOr<internal::SslUniquePtr<BIGNUM>> bn0 =
102 StringToBignum(absl::HexStringToBytes("000000"));
103 ASSERT_THAT(bn0, IsOk());
104
105 util::StatusOr<std::string> encoded0 =
106 internal::BignumToString(bn0->get(), BN_num_bytes(bn0->get()));
107 ASSERT_THAT(encoded0, IsOk());
108 EXPECT_EQ(*encoded0, absl::HexStringToBytes(""));
109 }
110
111 {
112 util::StatusOr<internal::SslUniquePtr<BIGNUM>> bn127 =
113 StringToBignum(absl::HexStringToBytes("00007F"));
114 ASSERT_THAT(bn127, IsOk());
115
116 util::StatusOr<std::string> encoded127 =
117 internal::BignumToString(bn127->get(), BN_num_bytes(bn127->get()));
118 ASSERT_THAT(encoded127, IsOk());
119 EXPECT_EQ(*encoded127, absl::HexStringToBytes("7F"));
120 }
121
122 {
123 util::StatusOr<internal::SslUniquePtr<BIGNUM>> bn128 =
124 StringToBignum(absl::HexStringToBytes("000080"));
125 ASSERT_THAT(bn128, IsOk());
126
127 util::StatusOr<std::string> encoded128 =
128 internal::BignumToString(bn128->get(), BN_num_bytes(bn128->get()));
129 ASSERT_THAT(encoded128, IsOk());
130 EXPECT_EQ(*encoded128, absl::HexStringToBytes("80"));
131 }
132
133 {
134 util::StatusOr<internal::SslUniquePtr<BIGNUM>> bn255 =
135 StringToBignum(absl::HexStringToBytes("0000FF"));
136 ASSERT_THAT(bn255, IsOk());
137
138 util::StatusOr<std::string> encoded255 =
139 internal::BignumToString(bn255->get(), BN_num_bytes(bn255->get()));
140 ASSERT_THAT(encoded255, IsOk());
141 EXPECT_EQ(*encoded255, absl::HexStringToBytes("FF"));
142 }
143
144 {
145 util::StatusOr<internal::SslUniquePtr<BIGNUM>> bn256 =
146 StringToBignum(absl::HexStringToBytes("000100"));
147 ASSERT_THAT(bn256, IsOk());
148
149 util::StatusOr<std::string> encoded256 =
150 internal::BignumToString(bn256->get(), BN_num_bytes(bn256->get()));
151 ASSERT_THAT(encoded256, IsOk());
152 EXPECT_EQ(*encoded256, absl::HexStringToBytes("0100"));
153 }
154 }
155
156
TEST(BignumToString,PadsWithLeadingZeros)157 TEST(BignumToString, PadsWithLeadingZeros) {
158 util::StatusOr<internal::SslUniquePtr<BIGNUM>> num =
159 StringToBignum(absl::HexStringToBytes("0102"));
160 ASSERT_THAT(num, IsOk());
161
162 util::StatusOr<std::string> encoded =
163 BignumToString(num->get(), /*len=*/ 2);
164 ASSERT_THAT(encoded, IsOk());
165 EXPECT_EQ(*encoded, absl::HexStringToBytes("0102"));
166
167 util::StatusOr<std::string> encodedWithPadding =
168 BignumToString(num->get(), /*len=*/ 5);
169 ASSERT_THAT(encodedWithPadding, IsOk());
170 EXPECT_EQ(*encodedWithPadding, absl::HexStringToBytes("0000000102"));
171
172 // try to encode with a value for len that is too short.
173 ASSERT_THAT(BignumToString(num->get(), /*len=*/1), Not(IsOk()));
174 }
175
TEST(BignumToString,RejectsNegativeNumbers)176 TEST(BignumToString, RejectsNegativeNumbers) {
177 // create a negative BIGNUM
178 util::StatusOr<internal::SslUniquePtr<BIGNUM>> number = HexToBignum("01");
179 ASSERT_THAT(number, IsOk());
180 BN_set_negative(number->get(), 1);
181 // Check that number is negative
182 ASSERT_EQ(CompareBignumWithWord(number->get(), /*word=*/0), -1);
183
184 ASSERT_THAT(BignumToString(number->get(), /*len=*/2), Not(IsOk()));
185 }
186
TEST(BnUtil,BignumToSecretData)187 TEST(BnUtil, BignumToSecretData) {
188 std::vector<std::string> bn_strs = {"0000000000000000", "0000000000000001",
189 "1000000000000000", "ffffffffffffffff",
190 "0fffffffffffffff", "00ffffffffffffff"};
191 for (const std::string& s : bn_strs) {
192 util::StatusOr<internal::SslUniquePtr<BIGNUM>> expected_bn = HexToBignum(s);
193 ASSERT_THAT(expected_bn, IsOk());
194
195 const std::string bn_bytes = absl::HexStringToBytes(s);
196 util::StatusOr<util::SecretData> result =
197 BignumToSecretData(expected_bn->get(), bn_bytes.size());
198 ASSERT_THAT(result, IsOk());
199 auto result_data = absl::string_view(
200 reinterpret_cast<char*>(result->data()), result->size());
201 EXPECT_EQ(absl::string_view(bn_bytes), result_data);
202 }
203 }
204
TEST(BnUtil,BignumToBinaryPadded)205 TEST(BnUtil, BignumToBinaryPadded) {
206 std::vector<std::string> bn_strs = {"0000000000000000", "0000000000000001",
207 "1000000000000000", "ffffffffffffffff",
208 "0fffffffffffffff", "00ffffffffffffff"};
209 for (const std::string& s : bn_strs) {
210 util::StatusOr<internal::SslUniquePtr<BIGNUM>> expected_bn = HexToBignum(s);
211 ASSERT_THAT(expected_bn, IsOk());
212
213 const std::string bn_bytes = absl::HexStringToBytes(s);
214 std::vector<char> buffer;
215 buffer.resize(bn_bytes.size());
216 util::Status res = BignumToBinaryPadded(
217 absl::MakeSpan(buffer.data(), buffer.size()), expected_bn->get());
218 ASSERT_THAT(res, IsOk());
219 auto buffer_data = absl::string_view(buffer.data(), buffer.size());
220 EXPECT_EQ(absl::string_view(bn_bytes), buffer_data);
221 }
222 }
223
224 // Make sure that for every buffer size that is smaller than the actual BN as a
225 // string, we get an error.
TEST(BnUtil,BufferToSmall)226 TEST(BnUtil, BufferToSmall) {
227 const std::string bn_str = "0fffffffffffffff";
228 util::StatusOr<internal::SslUniquePtr<BIGNUM>> expected_bn =
229 HexToBignum(bn_str);
230 ASSERT_THAT(expected_bn, IsOk());
231 const std::string bn_bytes = absl::HexStringToBytes(bn_str);
232 for (size_t buffer_size = 1; buffer_size < bn_bytes.size(); buffer_size++) {
233 {
234 std::vector<char> buffer;
235 buffer.resize(buffer_size);
236 util::Status result = BignumToBinaryPadded(
237 absl::MakeSpan(buffer.data(), buffer.size()), expected_bn->get());
238 EXPECT_THAT(result, Not(IsOk()));
239 }
240 {
241 util::StatusOr<std::string> result =
242 BignumToString(expected_bn->get(), buffer_size);
243 EXPECT_THAT(result, Not(IsOk()));
244 }
245 {
246 util::StatusOr<util::SecretData> result =
247 BignumToSecretData(expected_bn->get(), buffer_size);
248 EXPECT_THAT(result, Not(IsOk()));
249 }
250 }
251 }
252
TEST(BnUtil,CompareBignumWithWord)253 TEST(BnUtil, CompareBignumWithWord) {
254 internal::SslUniquePtr<BIGNUM> bn(BN_new());
255 BN_set_word(bn.get(), /*value=*/0x0fffffffffffffffUL);
256 EXPECT_EQ(CompareBignumWithWord(bn.get(), /*word=*/0x0fffffffffffffffL), 0);
257 std::vector<BN_ULONG> smaller_words = {
258 0x0000000000000000UL, 0x0000000000000001UL, 0x00ffffffffffffffUL};
259 for (const auto& word : smaller_words) {
260 EXPECT_GT(CompareBignumWithWord(bn.get(), word), 0)
261 << absl::StrCat("With value: 0x", absl::Hex(word));
262 }
263 std::vector<BN_ULONG> larger_words = {0x1000000000000000UL,
264 0xffffffffffffffffUL};
265 for (const auto& word : larger_words) {
266 EXPECT_LT(CompareBignumWithWord(bn.get(), word), 0)
267 << absl::StrCat("With value: 0x", absl::Hex(word));
268 }
269 }
270
271 } // namespace
272 } // namespace internal
273 } // namespace tink
274 } // namespace crypto
275