1 // Copyright 2017 Google Inc.
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 #ifndef TINK_UTIL_TEST_UTIL_H_
18 #define TINK_UTIL_TEST_UTIL_H_
19
20 #include <limits>
21 #include <memory>
22 #include <ostream>
23 #include <string>
24 #include <utility>
25
26 #include "absl/base/thread_annotations.h"
27 #include "absl/status/status.h"
28 #include "absl/strings/cord.h"
29 #include "absl/strings/match.h"
30 #include "absl/strings/str_cat.h"
31 #include "absl/strings/string_view.h"
32 #include "absl/synchronization/mutex.h"
33 #include "tink/aead.h"
34 #include "tink/aead/cord_aead.h"
35 #include "tink/deterministic_aead.h"
36 #include "tink/hybrid_decrypt.h"
37 #include "tink/hybrid_encrypt.h"
38 #include "tink/input_stream.h"
39 #include "tink/keyset_handle.h"
40 #include "tink/kms_client.h"
41 #include "tink/mac.h"
42 #include "tink/output_stream.h"
43 #include "tink/public_key_sign.h"
44 #include "tink/public_key_verify.h"
45 #include "tink/random_access_stream.h"
46 #include "tink/streaming_aead.h"
47 #include "tink/subtle/common_enums.h"
48 #include "tink/subtle/mac/stateful_mac.h"
49 #include "tink/util/buffer.h"
50 #include "tink/util/constants.h"
51 #include "tink/util/protobuf_helper.h"
52 #include "tink/util/status.h"
53 #include "tink/util/statusor.h"
54 #include "proto/common.pb.h"
55 #include "proto/ecdsa.pb.h"
56 #include "proto/ecies_aead_hkdf.pb.h"
57 #include "proto/ed25519.pb.h"
58 #include "proto/tink.pb.h"
59
60 namespace crypto {
61 namespace tink {
62 namespace test {
63
64 // Various utilities for testing.
65 ///////////////////////////////////////////////////////////////////////////////
66
67 // Reads the test file specified by `filename`, and returns its contents.
68 std::string ReadTestFile(absl::string_view filename);
69
70 // Converts a hexadecimal string into a string of bytes.
71 // Returns a status if the size of the input is odd or if the input contains
72 // characters that are not hexadecimal.
73 crypto::tink::util::StatusOr<std::string> HexDecode(absl::string_view hex);
74
75 // Converts a hexadecimal string into a string of bytes.
76 // Dies if the input is not a valid hexadecimal string.
77 std::string HexDecodeOrDie(absl::string_view hex);
78
79 // Converts a string of bytes into a hexadecimal string.
80 std::string HexEncode(absl::string_view bytes);
81
82 // Returns a temporary directory suitable for temporary testing files.
83 std::string TmpDir();
84
85 // Adds the given 'keyData' with specified status, key_id, and
86 // output_prefix_type to the keyset.
87 void AddKeyData(const google::crypto::tink::KeyData& key_data, uint32_t key_id,
88 google::crypto::tink::OutputPrefixType output_prefix,
89 google::crypto::tink::KeyStatusType key_status,
90 google::crypto::tink::Keyset* keyset);
91
92 // Adds the given 'key' with specified parameters and output_prefix_type=TINK
93 // to the specified 'keyset'.
94 void AddTinkKey(const std::string& key_type, uint32_t key_id,
95 const portable_proto::MessageLite& key,
96 google::crypto::tink::KeyStatusType key_status,
97 google::crypto::tink::KeyData::KeyMaterialType material_type,
98 google::crypto::tink::Keyset* keyset);
99
100 // Adds the given 'key' with specified parameters and output_prefix_type=LEGACY
101 // to the specified 'keyset'.
102 void AddLegacyKey(const std::string& key_type, uint32_t key_id,
103 const portable_proto::MessageLite& key,
104 google::crypto::tink::KeyStatusType key_status,
105 google::crypto::tink::KeyData::KeyMaterialType material_type,
106 google::crypto::tink::Keyset* keyset);
107
108 // Adds the given 'key' with specified parameters and output_prefix_type=RAW
109 // to the specified 'keyset'.
110 void AddRawKey(const std::string& key_type, uint32_t key_id,
111 const portable_proto::MessageLite& key,
112 google::crypto::tink::KeyStatusType key_status,
113 google::crypto::tink::KeyData::KeyMaterialType material_type,
114 google::crypto::tink::Keyset* keyset);
115
116 // Generates a fresh test key for ECIES-AEAD-HKDF for the given curve,
117 // using AesGcm with the specified key size as AEAD, and HKDF with 'hash_type'.
118 google::crypto::tink::EciesAeadHkdfPrivateKey GetEciesAesGcmHkdfTestKey(
119 subtle::EllipticCurveType curve_type, subtle::EcPointFormat ec_point_format,
120 subtle::HashType hash_type, uint32_t aes_gcm_key_size);
121
122 // Generates a fresh test key for ECIES-AEAD-HKDF for the given curve,
123 // using AesGcm with the specified key size as AEAD, and HKDF with 'hash_type'.
124 google::crypto::tink::EciesAeadHkdfPrivateKey GetEciesAesGcmHkdfTestKey(
125 google::crypto::tink::EllipticCurveType curve_type,
126 google::crypto::tink::EcPointFormat ec_point_format,
127 google::crypto::tink::HashType hash_type, uint32_t aes_gcm_key_size);
128
129 // Generates a fresh test key for ECIES-AEAD-HKDF for the given curve,
130 // using XChaCha20Poly1305 as AEAD, and HKDF with 'hash_type'.
131 google::crypto::tink::EciesAeadHkdfPrivateKey
132 GetEciesXChaCha20Poly1305HkdfTestKey(
133 google::crypto::tink::EllipticCurveType curve_type,
134 google::crypto::tink::EcPointFormat ec_point_format,
135 google::crypto::tink::HashType hash_type);
136
137 // Generates a fresh test key for ECIES-AEAD-HKDF for the given curve,
138 // using AesCtrHmac with the specified AEAD params, and HKDF with 'hash_type'.
139 google::crypto::tink::EciesAeadHkdfPrivateKey GetEciesAesCtrHmacHkdfTestKey(
140 google::crypto::tink::EllipticCurveType curve_type,
141 google::crypto::tink::EcPointFormat ec_point_format,
142 google::crypto::tink::HashType hash_type, uint32_t aes_ctr_key_size,
143 uint32_t aes_ctr_iv_size, google::crypto::tink::HashType hmac_hash_type,
144 uint32_t hmac_tag_size, uint32_t hmac_key_size);
145
146 // Generates a fresh test key for ECIES-AEAD-HKDF for the given curve,
147 // using AesSiv as the determinisitic AEAD, and HKDF with 'hash_type'.
148 google::crypto::tink::EciesAeadHkdfPrivateKey GetEciesAesSivHkdfTestKey(
149 google::crypto::tink::EllipticCurveType curve_type,
150 google::crypto::tink::EcPointFormat ec_point_format,
151 google::crypto::tink::HashType hash_type);
152
153 // Generates a fresh test key for EC DSA for the given 'curve_type', 'hash_type'
154 // and 'encoding'.
155 google::crypto::tink::EcdsaPrivateKey GetEcdsaTestPrivateKey(
156 subtle::EllipticCurveType curve_type, subtle::HashType hash_type,
157 subtle::EcdsaSignatureEncoding encoding);
158
159 // Generates a fresh test key for EC DSA for the given 'curve_type', 'hash_type'
160 // and 'encoding'.
161 google::crypto::tink::EcdsaPrivateKey GetEcdsaTestPrivateKey(
162 google::crypto::tink::EllipticCurveType curve_type,
163 google::crypto::tink::HashType hash_type,
164 google::crypto::tink::EcdsaSignatureEncoding encoding);
165
166 // TODO(ambrosin): Remove because it is unused.
167 // Generates a fresh test key for ED25519.
168 google::crypto::tink::Ed25519PrivateKey GetEd25519TestPrivateKey();
169
170 // Embeds the given Proto into a KeyData proto.
171 template <typename Proto>
AsKeyData(const Proto & proto,google::crypto::tink::KeyData::KeyMaterialType key_material_type)172 google::crypto::tink::KeyData AsKeyData(
173 const Proto& proto,
174 google::crypto::tink::KeyData::KeyMaterialType key_material_type) {
175 google::crypto::tink::KeyData result;
176 result.set_value(proto.SerializeAsString());
177 result.set_type_url(absl::StrCat(kTypeGoogleapisCom, proto.GetTypeName()));
178 result.set_key_material_type(key_material_type);
179 return result;
180 }
181
182 // Uses a z test on the given byte string, expecting all bits to be uniformly
183 // set with probability 1/2. Returns non ok status if the z test fails by more
184 // than 10 standard deviations.
185 //
186 // With less statistics jargon: This counts the number of bits set and expects
187 // the number to be roughly half of the length of the string. The law of large
188 // numbers suggests that we can assume that the longer the string is, the more
189 // accurate that estimate becomes for a random string. This test is useful to
190 // detect things like strings that are entirely zero.
191 //
192 // Note: By itself, this is a very weak test for randomness.
193 util::Status ZTestUniformString(absl::string_view bytes);
194 // Tests that the crosscorrelation of two strings of equal length points to
195 // independent and uniformly distributed strings. Returns non ok status if the z
196 // test fails by more than 10 standard deviations.
197 //
198 // With less statistics jargon: This xors two strings and then performs the
199 // ZTestUniformString on the result. If the two strings are independent and
200 // uniformly distributed, the xor'ed string is as well. A cross correlation test
201 // will find whether two strings overlap more or less than it would be expected.
202 //
203 // Note: Having a correlation of zero is only a necessary but not sufficient
204 // condition for independence.
205 util::Status ZTestCrosscorrelationUniformStrings(absl::string_view bytes1,
206 absl::string_view bytes2);
207 // Tests that the autocorrelation of a string points to the bits being
208 // independent and uniformly distributed. Rotates the string in a cyclic
209 // fashion. Returns non ok status if the z test fails by more than 10 standard
210 // deviations.
211 //
212 // With less statistics jargon: This rotates the string bit by bit and performs
213 // ZTestCrosscorrelationUniformStrings on each of the rotated strings and the
214 // original. This will find self similarity of the input string, especially
215 // periodic self similarity. For example, it is a decent test to find English
216 // text (needs about 180 characters with the current settings).
217 //
218 // Note: Having a correlation of zero is only a necessary but not sufficient
219 // condition for independence.
220 util::Status ZTestAutocorrelationUniformString(absl::string_view bytes);
221
222 // A dummy implementation of Aead-interface.
223 // An instance of DummyAead can be identified by a name specified
224 // as a parameter of the constructor.
225 class DummyAead : public Aead {
226 public:
DummyAead(absl::string_view aead_name)227 explicit DummyAead(absl::string_view aead_name) : aead_name_(aead_name) {}
228
229 // Computes a dummy ciphertext, which is concatenation of provided 'plaintext'
230 // with the name of this DummyAead.
Encrypt(absl::string_view plaintext,absl::string_view associated_data)231 crypto::tink::util::StatusOr<std::string> Encrypt(
232 absl::string_view plaintext,
233 absl::string_view associated_data) const override {
234 return absl::StrCat(aead_name_.size(), ":", associated_data.size(), ":",
235 aead_name_, associated_data, plaintext);
236 }
237
Decrypt(absl::string_view ciphertext,absl::string_view associated_data)238 crypto::tink::util::StatusOr<std::string> Decrypt(
239 absl::string_view ciphertext,
240 absl::string_view associated_data) const override {
241 std::string prefix =
242 absl::StrCat(aead_name_.size(), ":", associated_data.size(), ":",
243 aead_name_, associated_data);
244 if (!absl::StartsWith(ciphertext, prefix)) {
245 return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument,
246 "Dummy operation failed.");
247 }
248 ciphertext.remove_prefix(prefix.size());
249 return std::string(ciphertext);
250 }
251
252 private:
253 std::string aead_name_;
254 };
255
256 // A dummy implementation of CordAead-interface.
257 // An instance of DummyCordAead can be identified by a name specified
258 // as a parameter of the constructor.
259 class DummyCordAead : public CordAead {
260 public:
DummyCordAead(absl::string_view aead_name)261 explicit DummyCordAead(absl::string_view aead_name) : aead_(aead_name) {}
262
263 // Computes a dummy ciphertext, which is concatenation of provided 'plaintext'
264 // with the name of this DummyCordAead.
Encrypt(absl::Cord plaintext,absl::Cord associated_data)265 crypto::tink::util::StatusOr<absl::Cord> Encrypt(
266 absl::Cord plaintext, absl::Cord associated_data) const override {
267 auto ciphertext =
268 aead_.Encrypt(plaintext.Flatten(), associated_data.Flatten());
269
270 if (!ciphertext.ok()) return ciphertext.status();
271
272 absl::Cord ciphertext_cord;
273 ciphertext_cord.Append(ciphertext.value());
274 return ciphertext_cord;
275 }
276
Decrypt(absl::Cord ciphertext,absl::Cord associated_data)277 crypto::tink::util::StatusOr<absl::Cord> Decrypt(
278 absl::Cord ciphertext, absl::Cord associated_data) const override {
279 auto plaintext =
280 aead_.Decrypt(ciphertext.Flatten(), associated_data.Flatten());
281
282 if (!plaintext.ok()) return plaintext.status();
283
284 absl::Cord plaintext_cord;
285 plaintext_cord.Append(plaintext.value());
286 return plaintext_cord;
287 }
288
289 private:
290 DummyAead aead_;
291 };
292
293 // A dummy implementation of DeterministicAead-interface.
294 // An instance of DummyDeterministicAead can be identified by a name specified
295 // as a parameter of the constructor.
296 // The implementation is the same as DummyAead.
297 class DummyDeterministicAead : public DeterministicAead {
298 public:
DummyDeterministicAead(absl::string_view daead_name)299 explicit DummyDeterministicAead(absl::string_view daead_name)
300 : aead_(daead_name) {}
301
EncryptDeterministically(absl::string_view plaintext,absl::string_view associated_data)302 crypto::tink::util::StatusOr<std::string> EncryptDeterministically(
303 absl::string_view plaintext,
304 absl::string_view associated_data) const override {
305 return aead_.Encrypt(plaintext, associated_data);
306 }
307
DecryptDeterministically(absl::string_view ciphertext,absl::string_view associated_data)308 crypto::tink::util::StatusOr<std::string> DecryptDeterministically(
309 absl::string_view ciphertext,
310 absl::string_view associated_data) const override {
311 return aead_.Decrypt(ciphertext, associated_data);
312 }
313
314 private:
315 DummyAead aead_;
316 };
317
318 // A dummy implementation of StreamingAead-interface. An instance of
319 // DummyStreamingAead can be identified by a name specified as a parameter of
320 // the constructor. This name concatenated with 'associated_data' for a
321 // specific stream yields a header of an encrypted stream produced/consumed
322 // by DummyStreamingAead.
323 class DummyStreamingAead : public StreamingAead {
324 public:
DummyStreamingAead(absl::string_view streaming_aead_name)325 explicit DummyStreamingAead(absl::string_view streaming_aead_name)
326 : streaming_aead_name_(streaming_aead_name) {}
327
328 crypto::tink::util::StatusOr<std::unique_ptr<crypto::tink::OutputStream>>
NewEncryptingStream(std::unique_ptr<crypto::tink::OutputStream> ciphertext_destination,absl::string_view associated_data)329 NewEncryptingStream(
330 std::unique_ptr<crypto::tink::OutputStream> ciphertext_destination,
331 absl::string_view associated_data) const override {
332 return {absl::make_unique<DummyEncryptingStream>(
333 std::move(ciphertext_destination),
334 absl::StrCat(streaming_aead_name_, associated_data))};
335 }
336
337 crypto::tink::util::StatusOr<std::unique_ptr<crypto::tink::InputStream>>
NewDecryptingStream(std::unique_ptr<crypto::tink::InputStream> ciphertext_source,absl::string_view associated_data)338 NewDecryptingStream(
339 std::unique_ptr<crypto::tink::InputStream> ciphertext_source,
340 absl::string_view associated_data) const override {
341 return {absl::make_unique<DummyDecryptingStream>(
342 std::move(ciphertext_source),
343 absl::StrCat(streaming_aead_name_, associated_data))};
344 }
345
346 crypto::tink::util::StatusOr<
347 std::unique_ptr<crypto::tink::RandomAccessStream>>
NewDecryptingRandomAccessStream(std::unique_ptr<crypto::tink::RandomAccessStream> ciphertext_source,absl::string_view associated_data)348 NewDecryptingRandomAccessStream(
349 std::unique_ptr<crypto::tink::RandomAccessStream> ciphertext_source,
350 absl::string_view associated_data) const override {
351 return {absl::make_unique<DummyDecryptingRandomAccessStream>(
352 std::move(ciphertext_source),
353 absl::StrCat(streaming_aead_name_, associated_data))};
354 }
355
356 // Upon first call to Next() writes to 'ct_dest' the specifed 'header',
357 // and subsequently forwards all methods calls to the corresponding
358 // methods of 'cd_dest'.
359 class DummyEncryptingStream : public crypto::tink::OutputStream {
360 public:
DummyEncryptingStream(std::unique_ptr<crypto::tink::OutputStream> ct_dest,absl::string_view header)361 DummyEncryptingStream(std::unique_ptr<crypto::tink::OutputStream> ct_dest,
362 absl::string_view header)
363 : ct_dest_(std::move(ct_dest)),
364 header_(header),
365 after_init_(false),
366 status_(util::OkStatus()) {}
367
Next(void ** data)368 crypto::tink::util::StatusOr<int> Next(void** data) override {
369 if (!after_init_) { // Try to initialize.
370 after_init_ = true;
371 auto next_result = ct_dest_->Next(data);
372 if (!next_result.ok()) {
373 status_ = next_result.status();
374 return status_;
375 }
376 if (next_result.value() < header_.size()) {
377 status_ =
378 util::Status(absl::StatusCode::kInternal, "Buffer too small");
379 } else {
380 memcpy(*data, header_.data(), static_cast<int>(header_.size()));
381 ct_dest_->BackUp(next_result.value() - header_.size());
382 }
383 }
384 if (!status_.ok()) return status_;
385 return ct_dest_->Next(data);
386 }
387
BackUp(int count)388 void BackUp(int count) override {
389 if (after_init_ && status_.ok()) {
390 ct_dest_->BackUp(count);
391 }
392 }
393
Position()394 int64_t Position() const override {
395 if (after_init_ && status_.ok()) {
396 return ct_dest_->Position() - header_.size();
397 } else {
398 return 0;
399 }
400 }
Close()401 util::Status Close() override {
402 if (!after_init_) { // Call Next() to write the header to ct_dest_.
403 void* buf;
404 auto next_result = Next(&buf);
405 if (next_result.ok()) {
406 BackUp(next_result.value());
407 } else {
408 status_ = next_result.status();
409 return status_;
410 }
411 }
412 return ct_dest_->Close();
413 }
414
415 private:
416 std::unique_ptr<crypto::tink::OutputStream> ct_dest_;
417 std::string header_;
418 bool after_init_;
419 util::Status status_;
420 }; // class DummyEncryptingStream
421
422 // Upon first call to Next() tries to read from 'ct_source' a header
423 // that is expected to be equal to 'expected_header'. If this
424 // header matching succeeds, all subsequent method calls are forwarded
425 // to the corresponding methods of 'cd_source'.
426 class DummyDecryptingStream : public crypto::tink::InputStream {
427 public:
DummyDecryptingStream(std::unique_ptr<crypto::tink::InputStream> ct_source,absl::string_view expected_header)428 DummyDecryptingStream(std::unique_ptr<crypto::tink::InputStream> ct_source,
429 absl::string_view expected_header)
430 : ct_source_(std::move(ct_source)),
431 exp_header_(expected_header),
432 after_init_(false),
433 status_(util::OkStatus()) {}
434
Next(const void ** data)435 crypto::tink::util::StatusOr<int> Next(const void** data) override {
436 if (!after_init_) { // Try to initialize.
437 after_init_ = true;
438 auto next_result = ct_source_->Next(data);
439 if (!next_result.ok()) {
440 status_ = next_result.status();
441 if (status_.code() == absl::StatusCode::kOutOfRange) {
442 status_ = util::Status(absl::StatusCode::kInvalidArgument,
443 "Could not read header");
444 }
445 return status_;
446 }
447 if (next_result.value() < exp_header_.size()) {
448 status_ =
449 util::Status(absl::StatusCode::kInternal, "Buffer too small");
450 } else if (memcmp((*data), exp_header_.data(),
451 static_cast<int>(exp_header_.size()))) {
452 status_ = util::Status(absl::StatusCode::kInvalidArgument,
453 "Corrupted header");
454 }
455 if (status_.ok()) {
456 ct_source_->BackUp(next_result.value() - exp_header_.size());
457 }
458 }
459 if (!status_.ok()) return status_;
460 return ct_source_->Next(data);
461 }
462
BackUp(int count)463 void BackUp(int count) override {
464 if (after_init_ && status_.ok()) {
465 ct_source_->BackUp(count);
466 }
467 }
468
Position()469 int64_t Position() const override {
470 if (after_init_ && status_.ok()) {
471 return ct_source_->Position() - exp_header_.size();
472 } else {
473 return 0;
474 }
475 }
476
477 private:
478 std::unique_ptr<crypto::tink::InputStream> ct_source_;
479 std::string exp_header_;
480 bool after_init_;
481 util::Status status_;
482 }; // class DummyDecryptingStream
483
484 // Upon first call to PRead() tries to read from `ct_source` a header
485 // that is expected to be equal to `expected_header`. If this
486 // header matching succeeds, all subsequent method calls are forwarded
487 // to `ct_source->PRead`.
488 class DummyDecryptingRandomAccessStream
489 : public crypto::tink::RandomAccessStream {
490 public:
DummyDecryptingRandomAccessStream(std::unique_ptr<crypto::tink::RandomAccessStream> ct_source,absl::string_view expected_header)491 DummyDecryptingRandomAccessStream(
492 std::unique_ptr<crypto::tink::RandomAccessStream> ct_source,
493 absl::string_view expected_header)
494 : ct_source_(std::move(ct_source)), exp_header_(expected_header) {}
495
PRead(int64_t position,int count,crypto::tink::util::Buffer * dest_buffer)496 crypto::tink::util::Status PRead(
497 int64_t position, int count,
498 crypto::tink::util::Buffer* dest_buffer) override {
499 util::Status status = CheckHeader();
500 if (!status.ok()) {
501 return status;
502 }
503 status = dest_buffer->set_size(0);
504 if (!status.ok()) return status;
505 return ct_source_->PRead(position + exp_header_.size(), count,
506 dest_buffer);
507 }
508
size()509 util::StatusOr<int64_t> size() override {
510 util::Status status = CheckHeader();
511 if (!status.ok()) {
512 return status;
513 }
514 auto ct_size_result = ct_source_->size();
515 if (!ct_size_result.ok()) return ct_size_result.status();
516 auto pt_size = ct_size_result.value() - exp_header_.size();
517 if (pt_size >= 0) return pt_size;
518 return util::Status(absl::StatusCode::kUnavailable, "size not available");
519 }
520
521 private:
CheckHeader()522 util::Status CheckHeader()
523 ABSL_LOCKS_EXCLUDED(header_check_status_mutex_) {
524 absl::MutexLock lock(&header_check_status_mutex_);
525 if (header_check_status_.code() != absl::StatusCode::kUnavailable) {
526 return header_check_status_;
527 }
528 auto buf = std::move(util::Buffer::New(exp_header_.size()).value());
529 header_check_status_ =
530 ct_source_->PRead(0, exp_header_.size(), buf.get());
531 if (!header_check_status_.ok() &&
532 header_check_status_.code() != absl::StatusCode::kOutOfRange) {
533 return header_check_status_;
534 }
535 // EOF or Ok indicate a valid read has happened.
536 header_check_status_ = util::OkStatus();
537 // Invalid header.
538 if (buf->size() < exp_header_.size()) {
539 header_check_status_ = util::Status(absl::StatusCode::kInvalidArgument,
540 "Could not read header");
541 } else if (memcmp(buf->get_mem_block(), exp_header_.data(),
542 static_cast<int>(exp_header_.size()))) {
543 header_check_status_ = util::Status(absl::StatusCode::kInvalidArgument,
544 "Corrupted header");
545 }
546 return header_check_status_;
547 }
548
549 std::unique_ptr<crypto::tink::RandomAccessStream> ct_source_;
550 std::string exp_header_;
551 mutable absl::Mutex header_check_status_mutex_;
552 util::Status header_check_status_
553 ABSL_GUARDED_BY(header_check_status_mutex_) =
554 util::Status(absl::StatusCode::kUnavailable, "Uninitialized");
555 }; // class DummyDecryptingRandomAccessStream
556
557 private:
558 std::string streaming_aead_name_;
559 }; // class DummyStreamingAead
560
561 // A dummy implementation of HybridEncrypt-interface.
562 // An instance of DummyHybridEncrypt can be identified by a name specified
563 // as a parameter of the constructor.
564 class DummyHybridEncrypt : public HybridEncrypt {
565 public:
DummyHybridEncrypt(absl::string_view hybrid_name)566 explicit DummyHybridEncrypt(absl::string_view hybrid_name)
567 : dummy_aead_(absl::StrCat("DummyHybrid:", hybrid_name)) {}
568
569 // Computes a dummy ciphertext, which is concatenation of provided 'plaintext'
570 // with the name of this DummyHybridEncrypt.
Encrypt(absl::string_view plaintext,absl::string_view context_info)571 crypto::tink::util::StatusOr<std::string> Encrypt(
572 absl::string_view plaintext,
573 absl::string_view context_info) const override {
574 return dummy_aead_.Encrypt(plaintext, context_info);
575 }
576
577 private:
578 DummyAead dummy_aead_;
579 };
580
581 // A dummy implementation of HybridDecrypt-interface.
582 // An instance of DummyHybridDecrypt can be identified by a name specified
583 // as a parameter of the constructor.
584 class DummyHybridDecrypt : public HybridDecrypt {
585 public:
DummyHybridDecrypt(absl::string_view hybrid_name)586 explicit DummyHybridDecrypt(absl::string_view hybrid_name)
587 : dummy_aead_(absl::StrCat("DummyHybrid:", hybrid_name)) {}
588
589 // Decrypts a dummy ciphertext, which should be a concatenation
590 // of a plaintext with the name of this DummyHybridDecrypt.
Decrypt(absl::string_view ciphertext,absl::string_view context_info)591 crypto::tink::util::StatusOr<std::string> Decrypt(
592 absl::string_view ciphertext,
593 absl::string_view context_info) const override {
594 return dummy_aead_.Decrypt(ciphertext, context_info);
595 }
596
597 private:
598 DummyAead dummy_aead_;
599 };
600
601 // A dummy implementation of PublicKeySign-interface.
602 // An instance of DummyPublicKeySign can be identified by a name specified
603 // as a parameter of the constructor.
604 class DummyPublicKeySign : public PublicKeySign {
605 public:
DummyPublicKeySign(absl::string_view signature_name)606 explicit DummyPublicKeySign(absl::string_view signature_name)
607 : dummy_aead_(absl::StrCat("DummySign:", signature_name)) {}
608
609 // Computes a dummy signature, which is a concatenation of 'data'
610 // with the name of this DummyPublicKeySign.
Sign(absl::string_view data)611 crypto::tink::util::StatusOr<std::string> Sign(
612 absl::string_view data) const override {
613 return dummy_aead_.Encrypt("", data);
614 }
615
616 private:
617 DummyAead dummy_aead_;
618 };
619
620 // A dummy implementation of PublicKeyVerify-interface.
621 // An instance of DummyPublicKeyVerify can be identified by a name specified
622 // as a parameter of the constructor.
623 class DummyPublicKeyVerify : public PublicKeyVerify {
624 public:
DummyPublicKeyVerify(absl::string_view signature_name)625 explicit DummyPublicKeyVerify(absl::string_view signature_name)
626 : dummy_aead_(absl::StrCat("DummySign:", signature_name)) {}
627
628 // Verifies a dummy signature, should be a concatenation of the name
629 // of this DummyPublicKeyVerify with the provided 'data'.
Verify(absl::string_view signature,absl::string_view data)630 crypto::tink::util::Status Verify(absl::string_view signature,
631 absl::string_view data) const override {
632 return dummy_aead_.Decrypt(signature, data).status();
633 }
634
635 private:
636 DummyAead dummy_aead_;
637 };
638
639 // A dummy implementation of Mac-interface.
640 // An instance of DummyMac can be identified by a name specified
641 // as a parameter of the constructor.
642 class DummyMac : public Mac {
643 public:
DummyMac(const std::string & mac_name)644 explicit DummyMac(const std::string& mac_name)
645 : dummy_aead_(absl::StrCat("DummyMac:", mac_name)) {}
646
647 // Computes a dummy MAC, which is concatenation of provided 'data'
648 // with the name of this DummyMac.
ComputeMac(absl::string_view data)649 crypto::tink::util::StatusOr<std::string> ComputeMac(
650 absl::string_view data) const override {
651 return dummy_aead_.Encrypt("", data);
652 }
653
VerifyMac(absl::string_view mac,absl::string_view data)654 crypto::tink::util::Status VerifyMac(absl::string_view mac,
655 absl::string_view data) const override {
656 return dummy_aead_.Decrypt(mac, data).status();
657 }
658
659 private:
660 DummyAead dummy_aead_;
661 };
662
663 // A dummy implementation of Stateful Mac interface.
664 // An instance of DummyStatefulMac can be identified by a name specified
665 // as a parameter of the constructor.
666 // Over the same inputs, the DummyStatefulMac and DummyMac should give the same
667 // output; DummyStatefulMac builds and internal_state_ and calls DummyMac.
668 class DummyStatefulMac : public subtle::StatefulMac {
669 public:
DummyStatefulMac(const std::string & mac_name)670 explicit DummyStatefulMac(const std::string& mac_name)
671 : dummy_aead_(absl::StrCat("DummyMac:", mac_name)), buffer_("") {}
672
Update(absl::string_view data)673 util::Status Update(absl::string_view data) override {
674 absl::StrAppend(&buffer_, data);
675 return util::OkStatus();
676 }
Finalize()677 util::StatusOr<std::string> Finalize() override {
678 return dummy_aead_.Encrypt("", buffer_);
679 }
680
681 private:
682 DummyAead dummy_aead_;
683 std::string buffer_;
684 };
685
686 // A dummy implementation of KeysetWriter-interface.
687 class DummyKeysetWriter : public KeysetWriter {
688 public:
New(std::unique_ptr<std::ostream> destination_stream)689 static crypto::tink::util::StatusOr<std::unique_ptr<DummyKeysetWriter>> New(
690 std::unique_ptr<std::ostream> destination_stream) {
691 std::unique_ptr<DummyKeysetWriter> writer(
692 new DummyKeysetWriter(std::move(destination_stream)));
693 return std::move(writer);
694 }
695
Write(const google::crypto::tink::Keyset & keyset)696 crypto::tink::util::Status Write(
697 const google::crypto::tink::Keyset& keyset) override {
698 return crypto::tink::util::OkStatus();
699 }
700
Write(const google::crypto::tink::EncryptedKeyset & encrypted_keyset)701 crypto::tink::util::Status Write(
702 const google::crypto::tink::EncryptedKeyset& encrypted_keyset) override {
703 return crypto::tink::util::OkStatus();
704 }
705
706 private:
DummyKeysetWriter(std::unique_ptr<std::ostream> destination_stream)707 explicit DummyKeysetWriter(std::unique_ptr<std::ostream> destination_stream)
708 : destination_stream_(std::move(destination_stream)) {}
709
710 std::unique_ptr<std::ostream> destination_stream_;
711 };
712
713 // A dummy implementation of KmsClient-interface.
714 class DummyKmsClient : public KmsClient {
715 public:
DummyKmsClient(absl::string_view uri_prefix,absl::string_view key_uri)716 DummyKmsClient(absl::string_view uri_prefix, absl::string_view key_uri)
717 : uri_prefix_(uri_prefix), key_uri_(key_uri) {}
718
DoesSupport(absl::string_view key_uri)719 bool DoesSupport(absl::string_view key_uri) const override {
720 if (key_uri.empty()) return false;
721 if (key_uri_.empty()) return absl::StartsWith(key_uri, uri_prefix_);
722 return key_uri == key_uri_;
723 }
724
GetAead(absl::string_view key_uri)725 crypto::tink::util::StatusOr<std::unique_ptr<Aead>> GetAead(
726 absl::string_view key_uri) const override {
727 if (!DoesSupport(key_uri))
728 return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument,
729 "key_uri not supported");
730 return {absl::make_unique<DummyAead>(key_uri)};
731 }
732
733 ~DummyKmsClient() override = default;
734
735 private:
736 std::string uri_prefix_;
737 std::string key_uri_;
738 };
739
740 } // namespace test
741 } // namespace tink
742 } // namespace crypto
743
744 #endif // TINK_UTIL_TEST_UTIL_H_
745