xref: /aosp_15_r20/external/tink/cc/internal/bn_util_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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