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