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 #include "tink/util/test_util.h"
17
18 #include <algorithm>
19 #include <cstdint>
20 #include <memory>
21 #include <sstream>
22 #include <string>
23 #include <utility>
24
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 #include "absl/strings/string_view.h"
28 #include "tink/internal/test_random_access_stream.h"
29 #include "tink/output_stream.h"
30 #include "tink/random_access_stream.h"
31 #include "tink/subtle/random.h"
32 #include "tink/subtle/test_util.h"
33 #include "tink/util/buffer.h"
34 #include "tink/util/ostream_output_stream.h"
35 #include "tink/util/statusor.h"
36 #include "tink/util/test_matchers.h"
37 #include "proto/aes_gcm.pb.h"
38 #include "proto/tink.pb.h"
39
40 namespace crypto {
41 namespace tink {
42 namespace test {
43 namespace {
44
45 using ::crypto::tink::internal::TestRandomAccessStream;
46 using ::crypto::tink::test::StatusIs;
47 using ::google::crypto::tink::AesGcmKey;
48 using ::google::crypto::tink::KeyData;
49 using ::testing::Eq;
50 using ::testing::Not;
51
TEST(AsKeyDataTest,Basic)52 TEST(AsKeyDataTest, Basic) {
53 AesGcmKey key;
54 key.set_key_value(crypto::tink::subtle::Random::GetRandomBytes(11));
55
56 KeyData key_data = AsKeyData(key, KeyData::SYMMETRIC);
57
58 EXPECT_THAT(key_data.type_url(),
59 Eq("type.googleapis.com/google.crypto.tink.AesGcmKey"));
60 EXPECT_THAT(key_data.key_material_type(), Eq(KeyData::SYMMETRIC));
61 AesGcmKey deserialized_key;
62 EXPECT_TRUE(deserialized_key.ParseFromString(key_data.value()));
63 EXPECT_THAT(deserialized_key.key_value(), Eq(key.key_value()));
64 }
65
TEST(DummyTests,Aead)66 TEST(DummyTests, Aead) {
67 EXPECT_THAT(DummyAead("dummy").Encrypt("foo", "bar").value(),
68 Eq("5:3:dummybarfoo"));
69 }
70
TEST(DummyTests,AeadCord)71 TEST(DummyTests, AeadCord) {
72 absl::Cord plaintext;
73 plaintext.Append("foo");
74 absl::Cord aad;
75 aad.Append("bar");
76
77 EXPECT_THAT(DummyCordAead("dummy").Encrypt(plaintext, aad).value(),
78 Eq("5:3:dummybarfoo"));
79 }
80
TEST(DummyTests,AeadCordMultipleChunks)81 TEST(DummyTests, AeadCordMultipleChunks) {
82 absl::Cord plaintext;
83 plaintext.Append("f");
84 plaintext.Append("o");
85 plaintext.Append("o");
86 absl::Cord aad;
87 aad.Append("b");
88 aad.Append("a");
89 aad.Append("r");
90
91 EXPECT_THAT(DummyCordAead("dummy").Encrypt(plaintext, aad).value(),
92 Eq("5:3:dummybarfoo"));
93 }
94
TEST(ZTests,UniformString)95 TEST(ZTests, UniformString) {
96 EXPECT_THAT(ZTestUniformString(std::string(32, 0xaa)), IsOk());
97 EXPECT_THAT(ZTestUniformString(std::string(32, 0x00)), Not(IsOk()));
98 EXPECT_THAT(ZTestUniformString(subtle::Random::GetRandomBytes(32)), IsOk());
99 }
100
TEST(ZTests,CrossCorrelationUniformString)101 TEST(ZTests, CrossCorrelationUniformString) {
102 EXPECT_THAT(ZTestCrosscorrelationUniformStrings(std::string(32, 0xaa),
103 std::string(32, 0x99)),
104 IsOk());
105 EXPECT_THAT(ZTestCrosscorrelationUniformStrings(std::string(32, 0xaa),
106 std::string(32, 0xaa)),
107 Not(IsOk()));
108 EXPECT_THAT(
109 ZTestCrosscorrelationUniformStrings(subtle::Random::GetRandomBytes(32),
110 subtle::Random::GetRandomBytes(32)),
111 IsOk());
112 }
113
TEST(ZTests,AutocorrelationUniformString)114 TEST(ZTests, AutocorrelationUniformString) {
115 EXPECT_THAT(ZTestAutocorrelationUniformString(std::string(32, 0xaa)),
116 Not(IsOk()));
117 EXPECT_THAT(ZTestAutocorrelationUniformString(std::string(
118 "This is a text that is only ascii characters and therefore "
119 "not random. It needs quite a few characters before it has "
120 "enough to find a pattern, though, as it is text.")),
121 Not(IsOk()));
122 EXPECT_THAT(
123 ZTestAutocorrelationUniformString(subtle::Random::GetRandomBytes(32)),
124 IsOk());
125 }
126
TEST(DummyStreamingAead,DummyDecryptingStreamPreadAllAtOnceSucceeds)127 TEST(DummyStreamingAead, DummyDecryptingStreamPreadAllAtOnceSucceeds) {
128 const int stream_size = 1024;
129 std::string stream_content = subtle::Random::GetRandomBytes(stream_size);
130
131 auto ostream = std::make_unique<std::ostringstream>();
132 auto string_stream_buffer = ostream->rdbuf();
133 auto output_stream =
134 std::make_unique<util::OstreamOutputStream>(std::move(ostream));
135
136 DummyStreamingAead streaming_aead("Some AEAD");
137 util::StatusOr<std::unique_ptr<OutputStream>> encrypting_output_stream =
138 streaming_aead.NewEncryptingStream(std::move(output_stream), "Some AAD");
139 ASSERT_THAT(encrypting_output_stream.status(), IsOk());
140 ASSERT_THAT(subtle::test::WriteToStream(
141 encrypting_output_stream.value().get(), stream_content),
142 IsOk());
143
144 std::string ciphertext = string_stream_buffer->str();
145 auto test_random_access_stream =
146 std::make_unique<TestRandomAccessStream>(ciphertext);
147 util::StatusOr<std::unique_ptr<RandomAccessStream>>
148 decrypting_random_access_stream =
149 streaming_aead.NewDecryptingRandomAccessStream(
150 std::move(test_random_access_stream), "Some AAD");
151 ASSERT_THAT(decrypting_random_access_stream.status(), IsOk());
152
153 auto buffer = util::Buffer::New(ciphertext.size());
154 EXPECT_THAT((*decrypting_random_access_stream)
155 ->PRead(/*position=*/0, ciphertext.size(), buffer->get()),
156 StatusIs(absl::StatusCode::kOutOfRange));
157 EXPECT_EQ(stream_content,
158 std::string((*buffer)->get_mem_block(), (*buffer)->size()));
159 }
160
TEST(DummyStreamingAead,DummyDecryptingStreamPreadInChunksSucceeds)161 TEST(DummyStreamingAead, DummyDecryptingStreamPreadInChunksSucceeds) {
162 const int stream_size = 1024;
163 std::string stream_content = subtle::Random::GetRandomBytes(stream_size);
164
165 auto ostream = std::make_unique<std::ostringstream>();
166 auto string_stream_buffer = ostream->rdbuf();
167 auto output_stream =
168 std::make_unique<util::OstreamOutputStream>(std::move(ostream));
169
170 DummyStreamingAead streaming_aead("Some AEAD");
171 util::StatusOr<std::unique_ptr<OutputStream>> encrypting_output_stream =
172 streaming_aead.NewEncryptingStream(std::move(output_stream), "Some AAD");
173 ASSERT_THAT(encrypting_output_stream.status(), IsOk());
174 ASSERT_THAT(subtle::test::WriteToStream(
175 encrypting_output_stream.value().get(), stream_content),
176 IsOk());
177
178 std::string ciphertext = string_stream_buffer->str();
179 auto test_random_access_stream =
180 std::make_unique<TestRandomAccessStream>(ciphertext);
181 util::StatusOr<std::unique_ptr<RandomAccessStream>>
182 decrypting_random_access_stream =
183 streaming_aead.NewDecryptingRandomAccessStream(
184 std::move(test_random_access_stream), "Some AAD");
185 ASSERT_THAT(decrypting_random_access_stream.status(), IsOk());
186
187 int chunk_size = 10;
188 auto buffer = util::Buffer::New(chunk_size);
189 std::string plaintext;
190 int64_t position = 0;
191 util::Status status = (*decrypting_random_access_stream)
192 ->PRead(position, chunk_size, buffer->get());
193 while (status.ok()) {
194 plaintext.append((*buffer)->get_mem_block(), (*buffer)->size());
195 position += (*buffer)->size();
196 status = (*decrypting_random_access_stream)
197 ->PRead(position, chunk_size, buffer->get());
198 }
199 EXPECT_THAT(status, StatusIs(absl::StatusCode::kOutOfRange));
200 plaintext.append((*buffer)->get_mem_block(), (*buffer)->size());
201 EXPECT_EQ(stream_content, plaintext);
202 }
203
TEST(DummyStreamingAead,DummyDecryptingStreamPreadWithSmallerHeaderFails)204 TEST(DummyStreamingAead, DummyDecryptingStreamPreadWithSmallerHeaderFails) {
205 const int stream_size = 1024;
206 std::string stream_content = subtle::Random::GetRandomBytes(stream_size);
207
208 auto ostream = std::make_unique<std::ostringstream>();
209 auto output_stream =
210 std::make_unique<util::OstreamOutputStream>(std::move(ostream));
211
212 constexpr absl::string_view kStreamingAeadName = "Some AEAD";
213 constexpr absl::string_view kStreamingAeadAad = "Some associated data";
214
215 DummyStreamingAead streaming_aead(kStreamingAeadName);
216 util::StatusOr<std::unique_ptr<OutputStream>> encrypting_output_stream =
217 streaming_aead.NewEncryptingStream(std::move(output_stream),
218 kStreamingAeadAad);
219 ASSERT_THAT(encrypting_output_stream.status(), IsOk());
220 ASSERT_THAT(subtle::test::WriteToStream(
221 encrypting_output_stream.value().get(), stream_content),
222 IsOk());
223 // Stream content size is too small; DummyDecryptingStream expects
224 // absl::StrCat(kStreamingAeadName, kStreamingAeadAad).
225 std::string ciphertext = "Invalid header";
226 auto test_random_access_stream =
227 std::make_unique<TestRandomAccessStream>(ciphertext);
228 util::StatusOr<std::unique_ptr<RandomAccessStream>>
229 decrypting_random_access_stream =
230 streaming_aead.NewDecryptingRandomAccessStream(
231 std::move(test_random_access_stream), kStreamingAeadAad);
232 ASSERT_THAT(decrypting_random_access_stream.status(), IsOk());
233
234 int chunk_size = 10;
235 auto buffer = util::Buffer::New(chunk_size);
236 EXPECT_THAT(
237 (*decrypting_random_access_stream)
238 ->PRead(/*position=*/0, chunk_size, buffer->get()),
239 StatusIs(absl::StatusCode::kInvalidArgument, "Could not read header"));
240 EXPECT_THAT(
241 (*decrypting_random_access_stream)
242 ->PRead(/*position=*/0, chunk_size, buffer->get()),
243 StatusIs(absl::StatusCode::kInvalidArgument, "Could not read header"));
244 EXPECT_THAT(
245 (*decrypting_random_access_stream)->size().status(),
246 StatusIs(absl::StatusCode::kInvalidArgument, "Could not read header"));
247 }
248
TEST(DummyStreamingAead,DummyDecryptingStreamPreadWithCorruptedAadFails)249 TEST(DummyStreamingAead, DummyDecryptingStreamPreadWithCorruptedAadFails) {
250 const int stream_size = 1024;
251 std::string stream_content = subtle::Random::GetRandomBytes(stream_size);
252
253 auto ostream = std::make_unique<std::ostringstream>();
254 auto string_stream_buffer = ostream->rdbuf();
255 auto output_stream =
256 std::make_unique<util::OstreamOutputStream>(std::move(ostream));
257
258 constexpr absl::string_view kStreamingAeadName = "Some AEAD";
259 constexpr absl::string_view kStreamingAeadAad = "Some associated data";
260
261 DummyStreamingAead streaming_aead(kStreamingAeadName);
262 util::StatusOr<std::unique_ptr<OutputStream>> encrypting_output_stream =
263 streaming_aead.NewEncryptingStream(std::move(output_stream),
264 kStreamingAeadAad);
265 ASSERT_THAT(encrypting_output_stream.status(), IsOk());
266 ASSERT_THAT(subtle::test::WriteToStream(
267 encrypting_output_stream.value().get(), stream_content),
268 IsOk());
269 // Invalid associated data.
270 std::string ciphertext = string_stream_buffer->str();
271 auto test_random_access_stream =
272 std::make_unique<TestRandomAccessStream>(ciphertext);
273 util::StatusOr<std::unique_ptr<RandomAccessStream>>
274 decrypting_random_access_stream =
275 streaming_aead.NewDecryptingRandomAccessStream(
276 std::move(test_random_access_stream), "Some wrong AAD");
277 ASSERT_THAT(decrypting_random_access_stream.status(), IsOk());
278
279 int chunk_size = 10;
280 auto buffer = util::Buffer::New(chunk_size);
281 EXPECT_THAT((*decrypting_random_access_stream)
282 ->PRead(/*position=*/0, chunk_size, buffer->get()),
283 StatusIs(absl::StatusCode::kInvalidArgument, "Corrupted header"));
284 EXPECT_THAT((*decrypting_random_access_stream)
285 ->PRead(/*position=*/0, chunk_size, buffer->get()),
286 StatusIs(absl::StatusCode::kInvalidArgument, "Corrupted header"));
287 EXPECT_THAT((*decrypting_random_access_stream)->size().status(),
288 StatusIs(absl::StatusCode::kInvalidArgument, "Corrupted header"));
289 }
290
291 } // namespace
292 } // namespace test
293 } // namespace tink
294 } // namespace crypto
295