xref: /aosp_15_r20/external/tink/cc/subtle/streaming_mac_impl_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2019 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 
17 #include "tink/subtle/streaming_mac_impl.h"
18 
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "gtest/gtest.h"
25 #include "absl/status/status.h"
26 #include "tink/subtle/random.h"
27 #include "tink/subtle/test_util.h"
28 #include "tink/util/status.h"
29 #include "tink/util/statusor.h"
30 #include "tink/util/test_matchers.h"
31 #include "tink/util/test_util.h"
32 
33 namespace crypto {
34 namespace tink {
35 namespace subtle {
36 namespace {
37 
38 using ::crypto::tink::test::DummyStatefulMac;
39 using ::crypto::tink::test::IsOk;
40 using ::crypto::tink::test::StatusIs;
41 using ::testing::HasSubstr;
42 
43 class DummyStatefulMacFactory : public StatefulMacFactory {
44  public:
45   DummyStatefulMacFactory() = default;
46   ~DummyStatefulMacFactory() override = default;
47 
48   // Constructs a StatefulMac using the DummyStatefulMac, which creates
49   // returns a MAC of the header concatenated with the plaintext.
Create() const50   util::StatusOr<std::unique_ptr<StatefulMac>> Create() const override {
51     return std::unique_ptr<StatefulMac>(
52         absl::make_unique<DummyStatefulMac>("streaming mac:"));
53   }
54 };
55 
56 // A helper for creating an OutputStreamWithResult<std::string>,
57 // used for test validation for mac computation.
58 std::unique_ptr<OutputStreamWithResult<std::string>>
GetComputeMacOutputStream()59 GetComputeMacOutputStream() {
60   auto mac_factory = std::unique_ptr<StatefulMacFactory>(
61       absl::make_unique<DummyStatefulMacFactory>());
62   auto streaming_mac =
63       absl::make_unique<StreamingMacImpl>(std::move(mac_factory));
64   util::StatusOr<std::unique_ptr<OutputStreamWithResult<std::string>>>
65       stream_status = streaming_mac->NewComputeMacOutputStream();
66   EXPECT_THAT(stream_status, IsOk());
67   return std::move(*stream_status);
68 }
69 
70 // A helper for creating an OutputStreamWithResult<util::Status>,
71 // used for test validation for mac verification.
GetVerifyMacOutputStream(std::string expected_mac)72 std::unique_ptr<OutputStreamWithResult<util::Status>> GetVerifyMacOutputStream(
73     std::string expected_mac) {
74   auto mac_factory = std::unique_ptr<StatefulMacFactory>(
75       absl::make_unique<DummyStatefulMacFactory>());
76   auto streaming_mac =
77       absl::make_unique<StreamingMacImpl>(std::move(mac_factory));
78   util::StatusOr<std::unique_ptr<OutputStreamWithResult<util::Status>>>
79       stream_status = streaming_mac->NewVerifyMacOutputStream(expected_mac);
80   EXPECT_THAT(stream_status, IsOk());
81   return std::move(*stream_status);
82 }
83 
TEST(StreamingMacImplTest,ComputeEmptyMac)84 TEST(StreamingMacImplTest, ComputeEmptyMac) {
85   std::string expected_mac = "23:0:DummyMac:streaming mac:";
86   auto output_stream = GetComputeMacOutputStream();
87 
88   // Close stream and check result
89   auto close_status = output_stream->CloseAndGetResult();
90   EXPECT_THAT(close_status, IsOk());
91   EXPECT_EQ(*close_status, expected_mac);
92 }
93 
TEST(StreamingMacImplTest,ComputeSmallMac)94 TEST(StreamingMacImplTest, ComputeSmallMac) {
95   std::string text = "I am a small message";
96   std::string expected_mac =
97       "23:20:DummyMac:streaming mac:I am a small message";
98   auto output_stream = GetComputeMacOutputStream();
99 
100   // Write to the ComputeMacOutputStream
101   auto status = test::WriteToStream(output_stream.get(), text, false);
102   EXPECT_THAT(status, IsOk());
103   EXPECT_EQ(output_stream->Position(), text.size());
104 
105   // Close stream and check result
106   auto close_status = output_stream->CloseAndGetResult();
107   EXPECT_THAT(close_status, IsOk());
108   EXPECT_EQ(*close_status, expected_mac);
109 }
110 
TEST(StreamingMacImplTest,ComputeRandMac)111 TEST(StreamingMacImplTest, ComputeRandMac) {
112   std::vector<int> text_sizes = {0, 10, 100, 1000, 10000, 1000000};
113 
114   for (auto text_size : text_sizes) {
115     std::string text = Random::GetRandomBytes(text_size);
116     std::string expected_mac =
117         "23:" + std::to_string(text_size) + ":DummyMac:streaming mac:" + text;
118     auto output_stream = GetComputeMacOutputStream();
119 
120     // Write to the ComputeMacOutputStream
121     auto status = test::WriteToStream(output_stream.get(), text, false);
122     EXPECT_THAT(status, IsOk());
123     EXPECT_EQ(output_stream->Position(), text.size());
124 
125     // Close stream and check result
126     auto close_status = output_stream->CloseAndGetResult();
127     EXPECT_THAT(close_status, IsOk());
128     EXPECT_EQ(*close_status, expected_mac);
129   }
130 }
131 
TEST(StreamingMacImplTest,ComputeCheckStreamPosition)132 TEST(StreamingMacImplTest, ComputeCheckStreamPosition) {
133   std::string text = "I am a small message";
134   auto output_stream = GetComputeMacOutputStream();
135 
136   // Check position in first buffer returned by Next();
137   void* buffer;
138   util::StatusOr<int> next_result = output_stream->Next(&buffer);
139   EXPECT_THAT(next_result, IsOk());
140   int buffer_size = *next_result;
141   EXPECT_EQ(buffer_size, output_stream->Position());
142 
143   // Check position after calling BackUp
144   output_stream->BackUp(10);
145   EXPECT_EQ(buffer_size - 10, output_stream->Position());
146 }
147 
TEST(StreamingMacImplTest,ComputeCloseTwiceError)148 TEST(StreamingMacImplTest, ComputeCloseTwiceError) {
149   auto output_stream = GetComputeMacOutputStream();
150 
151   // Close stream
152   auto close_status = output_stream->CloseAndGetResult();
153 
154   // Try closing the stream again.
155   auto reclose_status = output_stream->Close();
156   EXPECT_FALSE(reclose_status.ok());
157   EXPECT_EQ(absl::StatusCode::kFailedPrecondition, reclose_status.code());
158 }
159 
TEST(StreamingMacImplTest,VerifyEmptyMac)160 TEST(StreamingMacImplTest, VerifyEmptyMac) {
161   std::string expected_mac = "23:0:DummyMac:streaming mac:";
162   auto output_stream = GetVerifyMacOutputStream(expected_mac);
163 
164   // Close stream and check result
165   auto close_status = output_stream->CloseAndGetResult();
166   EXPECT_THAT(close_status, IsOk());
167 }
168 
TEST(StreamingMacImplTest,VerifySmallMac)169 TEST(StreamingMacImplTest, VerifySmallMac) {
170   std::string text = "I am a small message";
171   std::string expected_mac =
172       "23:20:DummyMac:streaming mac:I am a small message";
173   auto output_stream = GetVerifyMacOutputStream(expected_mac);
174 
175   // Write to the VerifyMacOutputStream
176   auto status = test::WriteToStream(output_stream.get(), text, false);
177   EXPECT_THAT(status, IsOk());
178   EXPECT_EQ(output_stream->Position(), text.size());
179 
180   // Close stream and check result
181   auto close_status = output_stream->CloseAndGetResult();
182   EXPECT_THAT(close_status, IsOk());
183 }
184 
TEST(StreamingMacImplTest,VerifyEmptyMacFail)185 TEST(StreamingMacImplTest, VerifyEmptyMacFail) {
186   std::string expected_mac = "23:1:DummyMac:streaming mac:";
187   auto output_stream = GetVerifyMacOutputStream(expected_mac);
188 
189   // Close stream and check result
190   EXPECT_THAT(
191       output_stream->CloseAndGetResult(),
192       StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("Incorrect MAC")));
193 }
194 
TEST(StreamingMacImplTest,VerifySmallMacFail)195 TEST(StreamingMacImplTest, VerifySmallMacFail) {
196   std::string text = "I am a small message";
197   std::string expected_mac = "23:20:DummyMac:streaming mac:I am wrong message";
198   auto output_stream = GetVerifyMacOutputStream(expected_mac);
199 
200   // Write to the VerifyMacOutputStream
201   auto status = test::WriteToStream(output_stream.get(), text, false);
202   EXPECT_THAT(status, IsOk());
203   EXPECT_EQ(output_stream->Position(), text.size());
204 
205   // Close stream and check result
206   EXPECT_THAT(
207       output_stream->CloseAndGetResult(),
208       StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("Invalid MAC")));
209 }
210 
TEST(StreamingMacImplTest,VerifyRandMac)211 TEST(StreamingMacImplTest, VerifyRandMac) {
212   std::vector<int> text_sizes = {0, 10, 100, 1000, 10000, 1000000};
213 
214   for (auto text_size : text_sizes) {
215     std::string text = Random::GetRandomBytes(text_size);
216     std::string expected_mac =
217         "23:" + std::to_string(text_size) + ":DummyMac:streaming mac:" + text;
218     auto output_stream = GetVerifyMacOutputStream(expected_mac);
219 
220     // Write to the VerifyMacOutputStream
221     auto status = test::WriteToStream(output_stream.get(), text, false);
222     EXPECT_THAT(status, IsOk());
223     EXPECT_EQ(output_stream->Position(), text.size());
224 
225     // Close stream and check result
226     auto close_status = output_stream->CloseAndGetResult();
227     EXPECT_THAT(close_status, IsOk());
228   }
229 }
230 
TEST(StreamingMacImplTest,VerifyCheckStreamPosition)231 TEST(StreamingMacImplTest, VerifyCheckStreamPosition) {
232   std::string text = "I am a small message";
233   std::string expected_mac = "23:1:DummyMac:streaming mac:";
234   auto output_stream = GetVerifyMacOutputStream(expected_mac);
235 
236   // Check position in first buffer returned by Next();
237   void* buffer;
238   util::StatusOr<int> next_result = output_stream->Next(&buffer);
239   EXPECT_THAT(next_result, IsOk());
240   int buffer_size = *next_result;
241   EXPECT_EQ(buffer_size, output_stream->Position());
242 
243   // Check position after calling BackUp
244   output_stream->BackUp(10);
245   EXPECT_EQ(buffer_size - 10, output_stream->Position());
246 }
247 
TEST(StreamingMacImplTest,VerifyCloseTwiceError)248 TEST(StreamingMacImplTest, VerifyCloseTwiceError) {
249   std::string expected_mac = "23:0:DummyMac:streaming mac:";
250   auto output_stream = GetVerifyMacOutputStream(expected_mac);
251 
252   // Close stream
253   auto close_status = output_stream->CloseAndGetResult();
254 
255   // Try closing the stream again.
256   auto reclose_status = output_stream->Close();
257   EXPECT_FALSE(reclose_status.ok());
258   EXPECT_EQ(absl::StatusCode::kFailedPrecondition, reclose_status.code());
259 }
260 
261 }  // namespace
262 }  // namespace subtle
263 }  // namespace tink
264 }  // namespace crypto
265